洛谷 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
", ans);
}
原文地址:https://www.cnblogs.com/xuyixuan/p/9460788.html