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 ",ans); 64 } 65 }