洛谷 P1896 [SCOI2005]互不侵犯
题意简述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。
题解思路
预处理出所有状态中1的个数f[i],若超过k则为f[i] = -1
dp[i][j][k] 表示当前处理第i行,用过j个国王,当前行状态为k
枚举状态前一行l,
dp[i][j][k] += dp[i - 1][j - f[k]][l];
代码
#include <cstdio>
using namespace std;
typedef long long ll;
int n, k, x;
int f[1050];
ll ans;
ll dp[20][100][1050];
int main()
{
scanf("%d%d", &n, &k);
x = (1 << n) - 1;
for (register int i = 0; i <= x; ++i)
if (i << 1 & i || i >> 1 & i)
f[i] = -1;
else
{
int xx = __builtin_popcount(i);
if (xx > k) f[i] = -1;
else f[i] = xx;
}
dp[0][0][0] = 1;
for (register int i = 1; i <= n; ++i)
for (register int j = 0; j <= k; ++j)
for (register int l = 0; l <= x; ++l)
if (f[l] <= j && f[l] != -1)
for (register int h = 0; h <= x; ++h)
if (!(l & h) && !(l & h << 1) && !(l & h >> 1) && f[l] != -1)
dp[i][j][l] += dp[i - 1][j - f[l]][h];
for (register int i = 0; i <= x; ++i)
ans += dp[n][k][i];
printf("%lld\n", ans);
}