【BZOJ 1087】[SCOI2005]互不侵犯King
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
同学很早之前打表过了,orz
这题正解状压DP,f[i][s][k]表示第i行上一行的状态为S,选了k个
预处理出所有可行状态DP就好了
1 #include<cstdio> 2 #include<cstring> 3 #define ll long long 4 using namespace std; 5 int gs[520],a[520][11]; 6 bool pd[520]; 7 int n,K; 8 ll ans,f[11][520][90]; 9 bool ok(int x,int y){ 10 for(int i=1;i<=9;i++) if(a[x][i]&&(a[y][i]||a[y][i-1]||a[y][i+1])) return 0; 11 return 1; 12 } 13 14 int main(){ 15 scanf("%d%d",&n,&K); 16 memset(pd,1,sizeof(pd)); 17 for(int i=1;i<=(1<<n)-1;i++){ 18 int tmp=i,cnt=0; 19 while(tmp){ 20 a[i][++cnt]=tmp&1;gs[i]+=1&tmp; 21 tmp>>=1; 22 } 23 for(int j=1;j<=n;j++) if(a[i][j]==1&&a[i][j+1]==1){ 24 pd[i]=0;break; 25 } 26 if(pd[i]) f[1][i][gs[i]]+=1; 27 } 28 f[1][0][0]=1; 29 for(int i=2;i<=n;i++) 30 for(int j=0;j<=(1<<n)-1;j++){ 31 if(!pd[j]) continue; 32 for(int k=0;k<=(1<<n)-1;k++){ 33 if(ok(j,k)){ 34 for(int l=gs[k];l<=K;l++) 35 f[i][k][l]+=f[i-1][j][l-gs[k]]; 36 } 37 } 38 } 39 for(int i=0;i<=(1<<n)-1;i++)if (pd[i]) ans+=f[n][i][K]; 40 printf("%lld",ans); 41 }