Little Kings

sgu223:http://acm.sgu.ru/problem.php?contest=0&problem=223

题意:n*n的格子放k个国王,一共有多少种放发。

题解:简单的状压DP。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int n,m;
 7 const int N=(1<<11);
 8 long long dp[2][330][11*11];
 9 int num,s[N],ct[N];
10 void init(){
11    memset(dp,0,sizeof(dp));
12    memset(s,0,sizeof(s));
13    memset(ct,0,sizeof(ct));
14    num=0;
15 }
16 bool ok(int i){
17     return (i&(i<<1))==0;
18 }
19 int counts(int k){
20     int ans=0;
21     while(k>0){
22         ans+=k%2;
23         k/=2;
24     }
25     return ans;
26 }
27 bool judge(int s1,int s2){
28    if((s[s1]&s[s2])||((s[s1]<<1)&s[s2])||((s[s1]>>1)&s[s2]))return false;
29    return true;
30 }
31 void solve(){
32     for(int i=0;i<(1<<n);i++){
33         if(ok(i)){
34             num++;
35             s[num]=i;
36             ct[num]=counts(i);
37         }
38     }
39 }
40 int main(){
41     while(~scanf("%d%d",&n,&m)){
42         init();
43         solve();
44      for(int i=1;i<=num;i++){
45             dp[1][i][ct[i]]=1;
46         }
47         for(int i=2;i<=n;i++){
48             memset(dp[i&1],0,sizeof(dp[i&1]));
49             for(int j=1;j<=num;j++){//这一行的状态
50                 for(int k=ct[j];k<=m;k++){//这一行的个数
51                     for(int g=1;g<=num;g++){//上一行的状态
52                         if(judge(j,g)){
53                             dp[i&1][j][k]+=dp[(i-1)&1][g][k-ct[j]];
54                         }
55                     }
56                 }
57             }
58         }
59     long long ans=0;
60     for(int i=1;i<=num;i++){
61         ans+=dp[n&1][i][m];
62     }
63       printf("%I64d\n",ans);
64   }
65 }
View Code

 

posted on 2014-07-28 15:46  天依蓝  阅读(185)  评论(0编辑  收藏  举报

导航