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:
-
#include<iostream>
-
#include<cstdio>
-
using namespace std;
-
long long f[1<<20];
-
-
int main(){
-
long long n;
-
while(cin>>n){
-
memset(f,0,sizeof(f));
-
f[0] = 1;
-
long long i,t;
-
for( i=1; i< 1<<n; i++){
-
for( t=i; t>0; t -= (t & -t)){
-
f[i] += f[i & ~(t & -t)];
-
}
-
}
-
cout<<f[(1<<n)-1]<<endl;
-
}
-
}
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
-
#include<iostream>
-
#include<cstdio>
-
#include<algorithm>
-
#include<cstring>
-
using namespace std;
-
-
long long f[1<<20];
-
long long vist[22];
-
-
int main(){
-
long long n,m;
-
while(cin>>n>>m){
-
memset(f,0,sizeof(f));
-
memset(vist,0,sizeof(vist));
-
for(int i=0;i<m;i++){
-
int a,b;
-
cin>>a>>b;
-
vist[a] += 1<<(b-1);
-
}
-
f[0] = 1;
-
for(int i=1;i< 1<<n; i++){
-
int num = 0;
-
for(int j=i;j>0;j -= (j & -j)) num++;
-
for(int j=i;j>0;j -= (j & -j)) {
-
if(!(vist[num]&(j & -j))) f[i] += f[ i& ~(j & -j)];
-
}
-
}
-
cout<<f[(1<<n)-1]<<endl;
-
}
-
}
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
-
#include<iostream>
-
#include<cstdio>
-
#include<cmath>
-
#include<algorithm>
-
using namespace std;
-
int s[1<<10],c[1<<10],f[82][1<<9][21];
-
int n,m,num,flag,val;
-
-
void DFS(int ans,int pos,int flag){
-
if(pos>n) {
-
s[++num] = ans;
-
c[num] = flag;
-
return;
-
}
-
DFS(ans,pos+1,flag);
-
DFS(ans+(1<<pos-1),pos+2,flag+1);
-
}
-
-
int main(){
-
while(cin>>n>>m>>val){
-
if(n>m) swap(n,m);
-
num = 0;
-
DFS(0,1,0);
-
memset(f,0,sizeof(f));
-
-
for(int i=1;i<=num;i++)
-
f[1][s[i]][c[i]] = 1;
-
for(int i=2;i<=m;i++){
-
for(int j=1;j<=num;j++){
-
for(int r=1;r<=num;r++){
-
if(!(s[j]&s[r])){
-
for(int k=0;k<=val;k++){
-
if(k>=c[j]) f[i][s[j]][k] += f[i-1][s[r]][k-c[j]];
-
}
-
}
-
}
-
}
-
}
-
long long sum=0;
-
for(int i=1;i<=num;i++)
-
sum += f[m][s[i]][val];
-
cout<<sum<<endl;
-
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
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.
-
#include<iostream>
-
#include<cmath>
-
#include<algorithm>
-
#include<cstring>
-
#include<cstdio>
-
using namespace std;
-
long long f[11][1<<10][30];
-
int s[1<<10],c[1<<10],num;
-
int n,m,val;
-
-
void DFS(int ans,int pos,int flag){
-
if(pos>n){
-
s[++num] = ans;
-
c[num] = flag;
-
return ;
-
}
-
DFS(ans,pos+1,flag);
-
DFS(ans+(1<<pos-1),pos+2,flag+1);
-
}
-
-
int main(){
-
while(cin>>n>>m>>val){
-
num = 0;
-
DFS(0,1,0);
-
memset(f,0,sizeof(f));
-
for(int i=1;i<=num;i++)
-
f[1][s[i]][c[i]]=1;
-
for(int i=2;i<=n;i++){
-
for(int j=1;j<=num;j++){
-
for(int r=1;r<=num;r++){
-
if((s[j]&s[r]) || ((s[j]>>1)&s[r]) || ((s[j]<<1)&s[r])) continue;
-
for(int k=0;k<=val;k++){
-
if(k>=c[j]) f[i][s[j]][k] += f[i-1][s[r]][k-c[j]];
-
}
-
}
-
}
-
}
-
long long sum=0;
-
for(int i=1;i<=num;i++)
-
sum += f[n][s[i]][val];
-
cout<<sum<<endl;
-
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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.
-
#include<iostream>
-
#include<cstdio>
-
#include<algorithm>
-
#include<cstring>
-
#include<cmath>
-
using namespace std;
-
long long f[11][1<<10];
-
int n,m,s[1<<10],c[1<<10];
-
int num,ant,a[1<<10];
-
-
void DFS(int ans,int pos,int flag){
-
if(pos>m){
-
s[++num] = ans;
-
c[num] = flag;
-
return ;
-
}
-
DFS(ans,pos+1,flag);
-
DFS(ans+(1<<pos-1),pos+3,flag+1);
-
}
-
-
int main(){
-
while(cin>>n>>m>>ant){
-
int p,q;
-
for(int i=0;i<ant;i++){
-
cin>>p>>q;
-
a[p] += (1<<q-1);
-
}
-
memset(f,0,sizeof(f));
-
num = 0;
-
DFS(0,1,0);
-
-
for(int i=1;i<3 && i<=n;i++){
-
for(int j=1;j<=num;j++){
-
if(i==1){
-
if(a[i]&s[j]) continue;
-
f[i][s[j]]=c[j];
-
}
-
else {
-
if(a[i]&s[j]) continue;
-
for(int r=1;r<=num;r++){
-
if(a[i-1]&s[r]) continue;
-
if((s[j]&s[r])) continue;
-
f[i][s[j]] = max(f[i][s[j]],f[i-1][s[r]]+c[j]);
-
}
-
}
-
}
-
}
-
for(int i=3;i<=n;i++){
-
for(int j=1;j<=num;j++){
-
if(s[j]&a[i]) continue;
-
for(int r=1;r<=num;r++){
-
if((s[r]&a[i-1]) || (s[j]&s[r])) continue;
-
for(int h=1;h<=num;h++){
-
if((s[h]&a[i-3])||(s[j]&s[h])||(s[r]&s[h])) continue;
-
f[i][s[j]] = max(f[i][s[j]],f[i-2][s[h]]+c[j]+c[r]);
-
}
-
}
-
}
-
}
-
long long sum = 0;
-
for(int i=1;i<=num;i++)
-
sum = max(f[n][s[i]],sum);
-
cout<<sum<<endl;
-
}
-
}
-
-
-
-
-
-
-
-
-
-
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.
-
#include<iostream>
-
#include<cstdio>
-
#include<algorithm>
-
#include<cstring>
-
#include<cmath>
-
#include<string>
-
using namespace std;
-
long long f[12][1<<14];
-
int s1[1<<14],s2[1<<14],s[1<<14],ss[1<<14];
-
int n,m,num,flag;
-
bool vist[1<<14];
-
-
void DFS(int ans1,int ans2,int pos){
-
if(pos>n) {
-
if(pos==n+1) {
-
s1[++num] = ans1;
-
s2[num] = ans2;
-
}
-
return ;
-
}
-
DFS(ans1,ans2,pos+1);
-
DFS(ans1+(1<<pos-1)+(1<<pos),ans2,pos+2);
-
DFS(ans1+(1<<pos-1),ans2+(1<<pos-1),pos+1);
-
}
-
-
void dfs(int ans,int pos){
-
if(pos>n){
-
if(pos==n+1)
-
s[++flag] = ans;
-
return;
-
}
-
dfs(ans,pos+1);
-
dfs(ans+(1<<pos-1)+(1<<pos),pos+2);
-
}
-
-
int main(){
-
while(cin>>n>>m){
-
if(n==0 && m==0) break;
-
if(n%2 && m%2){ cout<<'0'<<endl; continue; }
-
if(n > m) swap(n,m);
-
if(n%2) swap(n,m);
-
if(m==1) { cout<<'1'<<endl; continue; }
-
num = 0; flag = 0;
-
DFS(0,0,1);
-
dfs(0,1);
-
memset(f,0,sizeof(f));
-
for(int i=1;i<=flag;i++)
-
f[1][s[i]] = 1;
-
int ant = (1<<n) - 1;
-
for(int i=1;i<=num;i++){
-
ss[i] = s1[i];
-
for(int j=1;j<=flag;j++){
-
if((s2[i]&s[j])) continue;
-
if((ant-s2[i])&(ant-s[j])) continue;
-
f[2][s1[i]] += f[1][s[j]];
-
}
-
}
-
sort(ss+1,ss+num);
-
int ans = 0;
-
ss[++ans] = ss[1];
-
for(int i=2;i<=num;i++){
-
if(ss[i]!=ss[i-1]) ss[++ans] = ss[i];
-
}
-
for(int i=3;i<=m;i++){
-
for(int j=1;j<=num;j++){
-
for(int r=1;r<=ans;r++){
-
if(s2[j]&ss[r]) continue;
-
if((ant-s2[j])&(ant-ss[r])) continue;
-
f[i][s1[j]] += f[i-1][ss[r]];
-
}
-
}
-
}
-
cout<<f[m][(1<<n)-1]<<endl;
-
}
-
}