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)

 

 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 }
View Code

 

posted @ 2020-02-17 01:00  _vv123  阅读(134)  评论(0编辑  收藏  举报