状压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 }

 

posted @ 2021-12-05 09:57  Hell0er  阅读(44)  评论(0编辑  收藏  举报