状压dp
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 using namespace std; 6 7 typedef long long LL; 8 const int MAXN=10; 9 const int MAXV=(1<<MAXN)+10; 10 const int MAXK=MAXN*MAXN; 11 int n,k; 12 LL dp[MAXN][MAXV][MAXK]; //第i行,状态为j,国王总个数为k的方案个数 13 14 int cnt[MAXV]; //每种状态有多少个1 15 inline void countOne() //统计 16 { 17 for (int i=0;i<(1<<n);i++) //枚举状态 18 { 19 int c=0; 20 for (int j=0;j<n;j++) //枚举位 21 { 22 if (i & (1<<j)) c++; 23 } 24 cnt[i]=c; 25 } 26 return; 27 } 28 29 int p[MAXV]; //满足同一行不矛盾的状态 30 int num=0; //状态个数 31 inline void checkLine() //同一行间互不攻击 32 { 33 for (int i=0;i<(1<<n);i++) //枚举状态 34 { 35 if (!((i & (i<<1)) | (i & (i>>1)))) p[++num]=i; 36 } 37 return; 38 } 39 40 int main() 41 { 42 scanf("%d%d",&n,&k); 43 44 countOne(); 45 checkLine(); 46 47 memset(dp,0,sizeof(dp)); 48 for (int i=1;i<=num;i++) 49 { 50 int x=p[i]; 51 dp[1][x][cnt[x]]=(LL)1; 52 } 53 54 for (int s=2;s<=n;s++) //枚举行 55 { 56 for (int j=1;j<=num;j++) //枚举本行状态 57 { 58 int y=p[j]; 59 for (int i=1;i<=num;i++) //枚举上一行状态 60 { 61 int x=p[i]; 62 if ((x & y) | (x & y<<1) | (x & y>>1)) continue; //上下两行间互相攻击,则跳过 63 for (int t=cnt[y];t<=k;t++) //枚举国王个数 64 { 65 dp[s][y][t]+=dp[s-1][x][t-cnt[y]]; 66 } 67 } 68 } 69 } 70 71 LL ans=0; 72 for (int i=1;i<=num;i++) 73 { 74 int x=p[i]; 75 ans+=dp[n][x][k]; 76 } 77 printf("%lld\n",ans); 78 79 return 0; 80 }