互不侵犯

有点类似八皇后问题,但是本题不能用搜索解决,而是通过状态压缩dp解决

\(f[i][j][k]\) 表示第 \(i\) 行状态为 \(j\) 总共放置了 \(k\) 个国王

在第 \(i\) 行时需要去考虑第 \(i - 1\) 行的状态,所以如果直接遍历需要的时间复杂度是 \(N * (1<< N)^2 * k^2\) 约为1e9, 这是不可接受的,因此需要去先筛选去掉不可能的状态,这里选择先去掉相邻状态,将可行的状态压缩为二进制存进数组,状态转移时从数组中读取可行状态再进一步筛选左上右上等

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, k, cnt;
int s[1 << 10], num[1 << 10];
ll f[10][1 << 10][10];
ll ans = 0;
int main () {
	cin >> n >> k;
	for (int i = 0; i < (1 << n); i++) {
		if (i & (i << 1)) continue;
		int sum = 0;
		for (int j = 0; j < n; j++) {
			if (i & (1 << j)) sum++;
		}
		s[++cnt] = i;
		num[cnt] = sum;
	}
	f[0][1][0] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= cnt; j++) {
			for (int p = 0; p <= k; p++) {
				for (int end = 1; end <= cnt; end++) {
					if (!(s[end] & s[j]) && !(s[end] & (s[j] << 1)) && !(s[end] & (s[j] >> 1))) {
						f[i][j][p] += f[i - 1][end][p - num[j]];
					}
				}
			}
		}
	}
	for (int i = 1; i <= cnt; i++) ans += f[n][i][k];
	cout << ans << endl;
	return 0;
}
posted @ 2022-08-09 17:24  misasteria  阅读(24)  评论(0编辑  收藏  举报