P1869 互不侵犯(简单的状压DP)
题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到周围的八个格子。
题解:首先只考虑某一行合法的摆法,只需保证选的格子不相邻就行。
可以把一行里合法的状态用一串二进制数存起来,每个数第i位的1表示第i列放置国王
比如101001是合法的,101101是不合法的
预处理每一种合法状态中,选择的格子数为 sta(x)
设f(i,j,l)表示已经处理到第i行,本行状态为j,总共已经选了l个的方案总数
设上一行的状态为x,如果x和j不矛盾就可以得到状态转移方程
f(i,j,l)=Σf(i-1,x,l-sta(x))
那么答案就是Σf(n,i,k)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 long long sta[2005], sit[2005], f[15][2005][105]; 6 7 int n, k, cnt; 8 9 void dfs(int x,int num,int cur){ 10 11 if(cur>=n){ 12 13 sit[++cnt]=x; 14 15 sta[cnt]=num; 16 17 return; 18 19 } 20 21 dfs(x,num,cur+1); 22 23 dfs(x+(1<<cur),num+1,cur+2); 24 25 } 26 27 int main(){ 28 29 cin>>n>>k; 30 31 dfs(0,0,0); 32 33 for(int i=1;i<=cnt;++i)f[1][i][sta[i]]=1; 34 35 for(int i=1;i<=n;++i) 36 37 for(int j=1;j<=cnt;++j) 38 39 for(int l=1;l<=cnt;++l){ 40 41 if (sit[j] & sit[l]) continue; 42 43 if ((sit[j] << 1) & sit[l]) continue; 44 45 if (sit[j] & (sit[l] << 1)) continue; 46 47 for(int p=sta[j];p<=k;++p) 48 49 f[i][j][p]+=f[i-1][l][p-sta[j]]; 50 51 } 52 53 long long ans = 0; 54 55 for(int i=1;i<=cnt;++i) 56 57 ans+=f[n][i][k]; 58 59 cout<<ans<<endl; 60 61 }