【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 } 

 

posted @ 2016-02-20 07:24  Alisahhh  阅读(231)  评论(0编辑  收藏  举报