NC20240 [SCOI2005]互不侵犯KING

题目链接

题目

题目描述

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。

国王能攻击到它上下左右,以及左上 左下右上右下八个方向上附近的各一个格子,共8个格子。

输入描述

只有一行,包含两个数N,K ( 1 ≤ N ≤ 9, 0 ≤ K ≤ N * N)

输出描述

方案数。

示例1

输入

3 2

输出

16

题解

知识点:状压dp。

状压dp,不过规定要摆 k 个(这里我用变量 t 保存),因此要开一个状态表示放了几个。设 dp[i][j][k] 表示放到第 i 行,一共放了 j 个,上一行的状态是 k 。枚举 i,j,k 和上一行的上一行状态 l 。满足 j < num[k] || (k & (k << 1)) == 1k 不合法,满足 (k & l) || ((k << 1) & l) || ((k >> 1) & l) == 1l 不合法。有转移方程:

dp[i][j][k]=l=02n1dp[i1][jnum[k]][l];

时间复杂度 O(nt4n)

空间复杂度 O(nt2n)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[15][90][1 << 10];
int num[1 << 10];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, t;
cin >> n >> t;
for (int i = 0;i <= (1 << n) - 1;i++) num[i] = __builtin_popcount(i);
dp[0][0][0] = 1;
for (int i = 1;i <= n;i++) {
for (int j = 0;j <= t;j++) {
for (int k = 0;k <= (1 << n) - 1;k++) {
if (j < num[k] || (k & (k << 1))) continue;
for (int l = 0;l <= (1 << n) - 1;l++) {
if ((k & l) || ((k << 1) & l) || ((k >> 1) & l)) continue;
dp[i][j][k] += dp[i - 1][j - num[k]][l];
}
}
}
}
ll ans = 0;
for (int i = 0;i <= (1 << n) - 1;i++) ans += dp[n][t][i];
cout << ans << '\n';
return 0;
}
posted @   空白菌  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示