本弱第一篇状压dp(在看了题解的前提下做的)
在n*n个格子内放m个国王,要求国王的四周即周围8个格子不能再有国王,求不同的放置方案数
将任意一行的一个状态看作是n位的二进制数,1表示放了国王,0表示没有放
dp[i][j][k] 表示前i行第j个状态,已经放置了k个国王的方案数;
can[i]第i个状态的数字,num[i]第i个状态的1的个数;
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
int n, m;//n*n的格子放m个
LL dp[11][1111][111];//前i行,第j个状态,共有k个国王的方案数
int can[1111], num[1111];//满足条件的数,以及它的含1的个数
int tot;
int getnum(int x)
{
int ret = 0;
while(x) ret += (x&1), x>>=1;
return num[tot] = ret;
}
int main()
{
int i, j, k, l, x, y;
scanf("%d %d", &n, &m);
memset(dp, 0, sizeof(dp));
int maxn = (1<<n)-1;
tot = 0;
for(i = 0; i <= maxn; ++i)
if(!(i&(i<<1)))//若二进制没有连续的1
can[++tot] = i, dp[1][tot][getnum(i)] = 1;
for(i = 2; i <= n; ++i)//枚举行号
for(j = 1; j <= tot; ++j)//枚举第i行的状态
{
x = can[j];
for(k = 1; k <= tot; ++k)//枚举第i-1行的状态
{
y = can[k];
if((x&y) || (x&(y<<1)) || (x&(y>>1))) continue;
for(l = 0; l <= m; ++l) dp[i][j][num[j]+l]+=dp[i-1][k][l];//更新状态
}
}
LL ans = 0;
for(i = 1; i <= tot; ++i) ans += dp[n][i][m];
printf("%lld\n", ans);
return 0;
}