
点击查看代码
#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;
}
- 状态表示
\(f[i][j][s]\) 表示所有只摆前 \(i\) 行,已经摆了 \(j\) 个国王,并且第 \(i\) 行的状态是 \(s\) 的所有方案的个数
- 状态计算
合法的状态才能转移,第 \(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\) 的个数)