[AcWing 1064] 小国王

image


点击查看代码
#include<iostream>
#include<cstring>
#include<vector>

using namespace std;

typedef long long LL;

const int N = 12, M = 1 << 10, K = 110;

int n, m;
vector<int> state;
int cnt[M];
vector<int> head[M];
LL f[N][K][M];

bool check(int x)
{
    for (int i = 0; i < n; i ++)
        if ((x >> i & 1) && ((x >> i + 1 & 1)))
            return false;
    return true;
}

int count(int x)
{
    int res = 0;
    for (int i = 0; i < n; i ++)
        res += x >> i & 1;
    return res;
}

int main()
{
    cin >> n >> m;
    for (int i = 0; i < 1 << n; i ++)
        if (check(i)) {
            state.push_back(i);
            cnt[i] = count(i);
        }
    for (auto a : state)
        for (auto b : state) {
            if ((a & b) == 0 && check(a | b))
                head[a].push_back(b);
        }   
    f[0][0][0] = 1;
    for (int i = 1; i <= n + 1; i ++)
        for (int j = 0; j <= m; j ++)
            for (auto a : state)
                for (auto b : head[a]) {
                    int c = cnt[a];
                    if (j >= c)
                        f[i][j][a] += f[i - 1][j - c][b];
                }
    cout << f[n + 1][m][0] << endl;
    return 0;
}

  1. 状态表示
    \(f[i][j][s]\) 表示所有只摆前 \(i\) 行,已经摆了 \(j\) 个国王,并且第 \(i\) 行的状态是 \(s\) 的所有方案的个数
  2. 状态计算
    合法的状态才能转移,第 \(i\) 行只与第 \(i - 1\) 行有关,合法的状态:
    设第 \(i\) 行的状态为 \(a\),第 \(i - 1\) 行的状态为 \(b\)
    ① 不能有两个国王在同一列,即 $a $ & $ b == 0$
    ② 不能有两个国王处在相邻的列,即 \(a \ | \ b\) 不能有两个连续的 $ 1 $
    满足上述条件的情况下:
    $f[i][j][a] $ += \(f[i - 1][j - count(a)][b]\) (\(count(a)\) 表示 \(a\) 的二进制表示中 \(1\) 的个数)
posted @ 2022-07-06 00:02  wKingYu  阅读(49)  评论(0)    收藏  举报