dp-chessboard problem (learning)

Reprinted from: http://blog.csdn.net/math_coder/article/details/9671581

If you don't understand the bitwise operation of the code, please understand the application of the lower operation first.

---------------------------------------------------------------------------------------------------------------------------

**************** This article is original. Before reading this article, please refer to the paper Zhou Wei's State Compression of Dynamic Planning ************

Question 1:

Place n vehicles on the checkerboard of n*n(n < 20) so that they can attack each other's rows and columns.

If we consider this problem from the perspective of combinatorics, it is very simple:

We put them one by one, the first line has n choices, the second line n-1,... The last line has one choice. According to the multiplication principle, the answer is n!

Here we introduce another solution: State Compressing Recursion (SCR).

  • We still put them in rows and rows.
  • Take the placement of chess pieces as a state, if a column has already placed chess pieces, it is 1, otherwise it is 0. In this way, a state can be represented by a binary number of up to 20 bits.
  • For example, if n=5, columns 1, 3, and 4 are already placed, then this state can be expressed as 01101 (from right to left). If f s is the number of schemes reaching state s, then we can try to establish the recursive relationship of F.
  • Consider n=5,s=01101
  • Because we put it line by line, we put it in the third line when we reach s. And because one line can only place one car, we know that state s must come from:

(1) The first two rows have chess pieces in columns 3 and 4 (the same below, regardless of order), and the third row has chess pieces in column 1;

(2) The first two rows have chess pieces in columns 1 and 4, and the third row has chess pieces in columns 3;

(3) The first two rows have chess pieces in columns 1 and 3, and the third row has chess pieces in columns 4.

These three cases are not intersecting each other, and there may only be three cases. According to the principle of addition, fs should be equal to the sum of these three cases. Write in recursive form.

         f(01101) = f(01100) + f(01001) + f(00101);

  • According to the ideas discussed above, we can get the solutions of the cited examples.

        f(0) = 1;

        f(s) = ·f(s-2^i);

The right-hand i+1 bit of s i s 1 (actually 1 in the binary representation of enumeration s)

The code is as follows:

  1. #include<iostream>  
  2. #include<cstdio>  
  3. using namespace std;  
  4. long long f[1<<20];  
  5.   
  6. int main(){  
  7.     long long n;  
  8.     while(cin>>n){  
  9.         memset(f,0,sizeof(f));  
  10.         f[0] = 1;  
  11.         long long i,t;  
  12.         for( i=1; i< 1<<n; i++){  
  13.             for( t=i; t>0; t -= (t & -t)){  
  14.                 f[i] += f[i & ~(t & -t)];  //Pay attention to understanding  
  15.             }  
  16.         }  
  17.         cout<<f[(1<<n)-1]<<endl;   
  18.     }  
  19. }  


 

Question 2: Place n cars on the checkerboard of n*n(n < 20), some lattices can't be put, so that they can't interact with each other.
Total number of attacks.
Input: Give you an n and an m to represent the size of the chessboard and the total number of checkerboards you can't put.
Next comes the coordinates of m rows, which indicate places that cannot be placed.
Output: Total number of eligible solutions.

0 means that it can be placed, and 1 means that it cannot be placed.
0 1 0
0 0 1
0 0 0
Input:
3 2 
1 2 
2 3 
Output: 3
Input:
4 1
1 1 
Output: 3 * 3 * 2 * 1 = 18
Tips:
1 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<algorithm>  
  4. #include<cstring>  
  5. using namespace std;  
  6.   
  7. long long f[1<<20];  
  8. long long vist[22];  
  9.   
  10. int main(){  
  11.     long long n,m;  
  12.     while(cin>>n>>m){  
  13.         memset(f,0,sizeof(f));  
  14.         memset(vist,0,sizeof(vist));  
  15.         for(int i=0;i<m;i++){  
  16.             int a,b;  
  17.             cin>>a>>b;  
  18.             vist[a] += 1<<(b-1); //If a position cannot be placed, compress it into integers.  
  19.         }  
  20.         f[0] = 1;  
  21.         for(int i=1;i< 1<<n; i++){  
  22.             int num = 0;  
  23.             for(int j=i;j>0;j -= (j & -j)) num++; //Calculate I. The number of states 1, i.e. the maximum number of rows included  
  24.             for(int j=i;j>0;j -= (j & -j)) {  
  25.                 if(!(vist[num]&(j & -j))) f[i] += f[ i& ~(j & -j)];//Determine whether the location can be placed.  
  26.             }  
  27.         }  
  28.         cout<<f[(1<<n)-1]<<endl;  
  29.     }  
  30. }  


Question 3: Give a chessboard of n*m (n, m < 80,n*m < 80), and put k(k < 20) pieces on the chessboard.
Make any two pieces not adjacent. Find the total number of alternatives that can be placed

  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<cmath>  
  4. #include<algorithm>   
  5. using namespace std;  
  6. int s[1<<10],c[1<<10],f[82][1<<9][21];   
  7. int n,m,num,flag,val;  
  8.   
  9. void DFS(int ans,int pos,int flag){  ///////////////////////  
  10.     if(pos>n) {   
  11.         s[++num] = ans;   
  12.         c[num] = flag;  
  13.         return;   
  14.     }  
  15.     DFS(ans,pos+1,flag);  
  16.     DFS(ans+(1<<pos-1),pos+2,flag+1);  
  17. }  
  18.   
  19. int main(){  
  20.     while(cin>>n>>m>>val){  
  21.         if(n>m) swap(n,m); //Row-column exchange  
  22.         num = 0;  //State Number Initialization  
  23.         DFS(0,1,0); //Parameters: Current status, location, number of 1, find the total number of qualified rows.  
  24.         memset(f,0,sizeof(f));  
  25.         ///////////////////////////////////////////  
  26.         for(int i=1;i<=num;i++) //The first line is initialized, and the number of 1 in the state is the initial number.  
  27.             f[1][s[i]][c[i]] = 1;  
  28.         for(int i=2;i<=m;i++){ //The first few lines  
  29.             for(int j=1;j<=num;j++){ //A state of a line  
  30.                 for(int r=1;r<=num;r++){ //A state of the previous line  
  31.                     if(!(s[j]&s[r])){ //The current and previous row states do not conflict.  
  32.                         for(int k=0;k<=val;k++){ //Enumerate the number of pieces in the current row.  
  33.                             if(k>=c[j]) f[i][s[j]][k] += f[i-1][s[r]][k-c[j]]; //Enumerate the current state with the state of the previous line  
  34.                         }  
  35.                     }  
  36.                 }  
  37.             }  
  38.         }  
  39.         long long sum=0;  
  40.         for(int i=1;i<=num;i++) //Cumulative total number of qualified last line  
  41.             sum += f[m][s[i]][val];  
  42.         cout<<sum<<endl;  
  43.     }  
  44. }  
  45. /* 
  46.  
  47. Because of the lack of data, I simulated several sets of data. 
  48. Input: 3.3.2 
  49. Output: 23 
  50.  
  51. Input: 2.2 
  52. Output: 2 
  53.  
  54. Input: 20 1 2 
  55. Output: 171 
  56.  
  57. */   


 

Question 4:
Place k kings (8 adjacent lattices) on a chessboard of n*n(n < 10) so that they cannot be attacked.
Number of schemes to attack each other.

 

  1. #include<iostream>   
  2. #include<cmath>  
  3. #include<algorithm>  
  4. #include<cstring>  
  5. #include<cstdio>  
  6. using namespace std;  
  7. long long f[11][1<<10][30];  
  8. int s[1<<10],c[1<<10],num;  
  9. int n,m,val;  
  10.       
  11. void DFS(int ans,int pos,int flag){  
  12.     if(pos>n){  
  13.         s[++num] = ans;  
  14.         c[num] = flag;  
  15.         return ;  
  16.     }  
  17.     DFS(ans,pos+1,flag);  
  18.     DFS(ans+(1<<pos-1),pos+2,flag+1);  
  19. }  
  20.   
  21. int main(){  
  22.     while(cin>>n>>m>>val){  
  23.         num = 0;  
  24.         DFS(0,1,0);  
  25.         memset(f,0,sizeof(f));   
  26.         for(int i=1;i<=num;i++)  
  27.             f[1][s[i]][c[i]]=1;  
  28.         for(int i=2;i<=n;i++){  
  29.             for(int j=1;j<=num;j++){ //Current row  
  30.                 for(int r=1;r<=num;r++){ //Previous row  
  31.                     if((s[j]&s[r]) || ((s[j]>>1)&s[r]) || ((s[j]<<1)&s[r])) continue//Eight Directions Judgment  
  32.                     for(int k=0;k<=val;k++){  
  33.                         if(k>=c[j]) f[i][s[j]][k] += f[i-1][s[r]][k-c[j]];  
  34.                     }  
  35.                 }  
  36.             }  
  37.         }  
  38.         long long sum=0;  
  39.         for(int i=1;i<=num;i++)  
  40.             sum += f[n][s[i]][val];  
  41.         cout<<sum<<endl;  
  42.     }  
  43. }  
  44. /* 
  45.  
  46. Input: 3.3.2 
  47. Output: 16 
  48.  
  49. Input: 2 2 2 1 
  50. Output: 4 
  51.  
  52. Input: 3 3 3 3 
  53. Output: 8 
  54.  
  55. Input: 9 9 9 2 
  56. Output: 1968 
  57.  
  58. */   

Topic 5: Give a chessboard of n*m(n < 100,m < 10), some lattices can not place chessboard. Seek the most in

How many pieces are placed on the board so that there are at least two spaces between any two pieces in each row and column.  

  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<algorithm>  
  4. #include<cstring>  
  5. #include<cmath>  
  6. using namespace std;  
  7. long long f[11][1<<10];  
  8. int n,m,s[1<<10],c[1<<10];  
  9. int num,ant,a[1<<10];  
  10.   
  11. void DFS(int ans,int pos,int flag){  
  12.     if(pos>m){  
  13.         s[++num] = ans;  
  14.         c[num] = flag;  
  15.         return ;  
  16.     }  
  17.     DFS(ans,pos+1,flag);  
  18.     DFS(ans+(1<<pos-1),pos+3,flag+1);  
  19. }  
  20.   
  21. int main(){  
  22.     while(cin>>n>>m>>ant){  
  23.         int p,q;  
  24.         for(int i=0;i<ant;i++){  
  25.             cin>>p>>q;  
  26.             a[p] += (1<<q-1);  
  27.         }  
  28.         memset(f,0,sizeof(f));  
  29.         num = 0;  
  30.         DFS(0,1,0);  
  31.       //  for(int i=1;i<=num;i++) cout<<s[i]<<" "<<c[i]<<endl;  
  32.         for(int i=1;i<3 && i<=n;i++){  
  33.             for(int j=1;j<=num;j++){ //When i==2, it represents the current row, and when i==1, it represents the current row.  
  34.                 if(i==1){  
  35.                     if(a[i]&s[j]) continue;  //Cannot be placed  
  36.                     f[i][s[j]]=c[j];  
  37.                 }  
  38.                 else {  
  39.                     if(a[i]&s[j]) continue;  //Cannot be placed  
  40.                     for(int r=1;r<=num;r++){ //Cannot be placed and does not conflict with state 1, indicating the state of the previous row  
  41.                         if(a[i-1]&s[r]) continue;  //Can not be placed.  
  42.                         if((s[j]&s[r])) continue;  
  43.                         f[i][s[j]] = max(f[i][s[j]],f[i-1][s[r]]+c[j]);   
  44.                     }  
  45.                 }  
  46.             }  
  47.         }  
  48.         for(int i=3;i<=n;i++){  
  49.             for(int j=1;j<=num;j++){//Current row  
  50.                 if(s[j]&a[i]) continue;  
  51.                 for(int r=1;r<=num;r++){//The previous line i-1  
  52.                     if((s[r]&a[i-1]) || (s[j]&s[r])) continue;  
  53.                     for(int h=1;h<=num;h++){//i-2  
  54.                         if((s[h]&a[i-3])||(s[j]&s[h])||(s[r]&s[h])) continue;  
  55.                         f[i][s[j]] = max(f[i][s[j]],f[i-2][s[h]]+c[j]+c[r]);  
  56.                     }  
  57.                 }  
  58.             }  
  59.         }  
  60.         long long sum = 0;  
  61.         for(int i=1;i<=num;i++)   
  62.             sum = max(f[n][s[i]],sum);  
  63.         cout<<sum<<endl;  
  64.     }  
  65. }   
  66. /* 
  67.  
  68. Input: 
  69. 3 3 3 
  70. 2 1 
  71. 2 2 
  72. 2 3 
  73. Output: 2 
  74.  
  75. */  


Topic 6:
Give a checkerboard of n*m(1 < n, m < 11) and cover it with a rectangular domino of 1*2 without overlapping.
Chess board, to find the number of programs covered.


  1. #include<iostream>  
  2. #include<cstdio>   
  3. #include<algorithm>  
  4. #include<cstring>  
  5. #include<cmath>  
  6. #include<string>  
  7. using namespace std;  
  8. long long f[12][1<<14];  
  9. int s1[1<<14],s2[1<<14],s[1<<14],ss[1<<14];  
  10. int n,m,num,flag;  
  11. bool vist[1<<14];  
  12.   
  13. void DFS(int ans1,int ans2,int pos){  
  14.     if(pos>n) {  
  15.         if(pos==n+1) {  
  16.             s1[++num] = ans1;  
  17.             s2[num] = ans2;  
  18.         }  
  19.         return ;  
  20.     }  
  21.     DFS(ans1,ans2,pos+1); //Not put  
  22.     DFS(ans1+(1<<pos-1)+(1<<pos),ans2,pos+2); //Horizontally  
  23.     DFS(ans1+(1<<pos-1),ans2+(1<<pos-1),pos+1); //Vertical placement  
  24. }  
  25.   
  26. void dfs(int ans,int pos){  
  27.     if(pos>n){  
  28.         if(pos==n+1)  
  29.             s[++flag] = ans;  
  30.         return;  
  31.     }  
  32.     dfs(ans,pos+1);  
  33.     dfs(ans+(1<<pos-1)+(1<<pos),pos+2);  
  34. }  
  35.   
  36. int main(){  
  37.     while(cin>>n>>m){  
  38.         if(n==0 && m==0) break;  
  39.         if(n%2 && m%2){ cout<<'0'<<endl; continue; }  
  40.         if(n > m) swap(n,m);  
  41.         if(n%2) swap(n,m);  
  42.         if(m==1) { cout<<'1'<<endl; continue; }  
  43.         num = 0; flag = 0;  
  44.         DFS(0,0,1);  
  45.         dfs(0,1); //All-state search in the first line  
  46.         memset(f,0,sizeof(f));   
  47.         for(int i=1;i<=flag;i++)  
  48.             f[1][s[i]] = 1;  
  49.         int ant = (1<<n) - 1;  
  50.         for(int i=1;i<=num;i++){ //Second elements  
  51.             ss[i] = s1[i];  
  52.             for(int j=1;j<=flag;j++){ //First line  
  53.                 if((s2[i]&s[j])) continue;  
  54.                 if((ant-s2[i])&(ant-s[j])) continue//Processing the same 0  
  55.                 f[2][s1[i]] += f[1][s[j]];  
  56.             }  
  57.         }  
  58.         sort(ss+1,ss+num);  
  59.         int ans = 0;  
  60.         ss[++ans] = ss[1];  
  61.         for(int i=2;i<=num;i++){  //Eliminate the same and avoid double counting.  
  62.             if(ss[i]!=ss[i-1]) ss[++ans] = ss[i];  
  63.         }  
  64.         for(int i=3;i<=m;i++){ //Third elements  
  65.             for(int j=1;j<=num;j++){//i. Line state traversal  
  66.                 for(int r=1;r<=ans;r++){ //(i-1) Line ***** Same s1[r] can only calculate WA N once for a long time.  
  67.                     if(s2[j]&ss[r]) continue;  
  68.                     if((ant-s2[j])&(ant-ss[r])) continue;  
  69.                     f[i][s1[j]] += f[i-1][ss[r]];  
  70.                 }   
  71.             }  
  72.         }   
  73.         cout<<f[m][(1<<n)-1]<<endl;  
  74.     }  
  75. }  

Posted by goodluck4287 on Fri, 29 Mar 2019 05:00:30 -0700