bzoj1087:[SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2358  Solved: 1380
[Submit][Status][Discuss]

Description

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

方案数。

Sample Input

3 2

Sample Output

16
 
题解:
  状压DP的特征还是很显然的,把每一行放国王表示成1,不放国王表示成0,由此可以得到一个01串,此01串所对应的十进制数就是压缩后的状态。
  显然对于每一行的情况只由上一行决定,因此满足DP的无后效性。
  f[i][k][p]表示第i行用情况k,第i-1行用情况p,state[i]表示情况i所对应的十进制数,cost[i]表示情况i所耗费的国王数。
  因为N<=9,所以对于情况数而言不会超过2^9个,但明显其中肯定有某两个国王相邻的,这样本行就矛盾了,何谈与上一行进行比较?由此我们可以先预处理出所有情况,放在state[]和cost[]中,状态转移方程见下面的代码。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 LL N,K;
 5 LL cnt;
 6 LL state[1<<10+10],cost[1<<10+10];
 7 LL f[11][1<<10][110];//f[i][j][k]//第i行用情况j,总共用了k个国王 
 8 LL ANS;
 9 int main(){
10     scanf("%lld%lld",&N,&K);
11     for(LL i=0;i<=(1<<N)-1;i++){
12         LL tmp=i;
13         if( (((i<<1)&i)) || ((i>>1)&i) ) continue;
14         cost[++cnt]=tmp%2;
15         while(tmp=(tmp>>1)) cost[cnt]+=tmp%2;
16         if(cost[cnt]<=K) state[cnt]=i;
17         else cost[cnt--]=0;
18     }
19     for(LL i=1;i<=cnt;i++){
20         f[1][i][cost[i]]=1;
21     }
22     for(LL i=2;i<=N;i++){//枚举2~N行 
23         for(LL j=1;j<=cnt;j++){//枚举第i行的状态 
24             for(LL p=1;p<=cnt;p++){//枚举第i-1行的状态 
25                 if(((state[j]<<1)&state[p])||((state[j]>>1)&state[p])||(state[j]&state[p])) continue;//不会有相互吃的情况 
26                 for(LL k1=0;k1<=K;k1++){//枚举第i-1行及以前用的国王数 
27                     if(k1+cost[j]<=K) f[i][j][k1+cost[j]]+=f[i-1][p][k1];
28                 }
29             }
30         }
31     }
32     for(LL i=1;i<=cnt;i++){
33         ANS+=f[N][i][K];
34     }
35     cout<<ANS;
36     return 0;
37 }

 

 
posted @ 2015-12-27 15:45  CXCXCXC  阅读(209)  评论(0编辑  收藏  举报