题目大意: 有n*n的棋盘上放k个国王。国王可以攻击与它相邻的八个格子。现在要使国王不相互攻击,有多少种放置的方案数。一个格子不能放两个国王。
n<=10,k<=n*n。
分析:简单的状态压缩DP。f[i][state][j]表示第i行放置国王的状态为state,前i行一共放了j个国王的方案数,state为位压缩表示的状态,某位为1,表示该处放了国王,为0表示没有放。合法的state状态数是有限的,所以,可以预处理出一行当中所有合法的state状态,保存在数组中。
f[i][p1][j]=∑(f[i-1][p2][j-cnts[state]]) {(state[p2]&state[p1])==0&&((state[p2]>>1)&state[p1]==0)&&((state[p2]<<1)&state[p1]==0)}
最后的答案即为∑f[n][j][k] {枚举j}
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int n,k,num=0,s[1200],c[1200]; 6 long long f[2][1100][120]; 7 void dfs(int i,int state,int cnt) 8 { 9 if(i>=n) 10 {s[++num]=state; 11 c[num]=cnt; 12 return; 13 } 14 dfs(i+1,state<<1,cnt); 15 if(state&1)return; 16 dfs(i+1,(state<<1)+1,cnt+1); 17 } 18 int main() 19 { 20 while(scanf("%d%d",&n,&k)!=-1) 21 { 22 memset(f,0,sizeof f); 23 num=0; 24 dfs(0,0,0); 25 for(int i=1;i<=n;i++) 26 { 27 for(int j=1;j<=num;j++) 28 {if(i==1)f[i&1][j][c[j]]=1; 29 else 30 for(int p=c[j];p<=k;p++) 31 { 32 f[i&1][j][p]=0; 33 for(int x=1;x<=num;x++) 34 { 35 if(c[x]+c[j]<=p&&(s[x]&s[j])==0&&((s[x]&(s[j]<<1))==0)&&((s[x]&(s[j]>>1))==0)) 36 f[i&1][j][p]+=f[!(i&1)][x][p-c[j]]; 37 } 38 } 39 } 40 } 41 long long ans=0; 42 for(int j=1;j<=num;j++) 43 ans+=f[n&1][j][k]; 44 printf("%I64d\n",ans); 45 } 46 }