当前位置:网站首页>【[SCOI2005] 互不侵犯】【状压DP(含概念讲解)】
【[SCOI2005] 互不侵犯】【状压DP(含概念讲解)】
2022-08-02 15:28:00 【Eternity_GQM】
文章目录
什么是状压DP
状压 DP 是动态规划的一种,通过将状态压缩为整数来达到优化转移的目的。
如下图所示,可以用0/1表示状态,然后转换为十进制数进行存储,大大减少存储空间。

[SCOI2005] 互不侵犯
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式
所得的方案数
样例 #1
样例输入 #1
3 2
样例输出 #1
16
思路分析
数组f[i][st][j]的定义,以及状态转移方程:

不合法检验:
行内不能相邻,行间要检验三位。

st 的范围(状态数组的大小):

代码
int n, k;
ll f[9][1 << 9][82], ans;
int c(int st){
//返回st的二进制中1的个数
int cnt = 0;
while(st){
if(st%2)
cnt++;
st /= 2;
}
return cnt;
}
bool check1(int st){
//同行检验
for (int i = 0; i < n - 1;i++)
if ((st & (1 << i)) && (st & (1 << (i + 1))))
return false;
return true;
}
bool check2(int st,int st2){
//与上一行的检验
for (int i = 0; i < n;i++){
if (st & (1 << i)){
if (st2 & (1 << i))
return false;
else if (i + 1 < n && (st2 & (1 << (i + 1))))
return false;
else if (i - 1 < n && (st2 & (1 << (i - 1))))
return false;
}
}
return true;
}
void solve(){
cin >> n >> k;
for (int i = 0; i < n;i++){
for (int st = 0; st < (1 << n);st++){
if(!check1(st))
continue;
if (i == 0)
f[i][st][c(st)] = 1;
else{
for (int j = c(st); j <= k;j++){
for (int st2 = 0; st2 < (1 << n);st2++){
if(!check1(st2)||!check2(st,st2))
continue;
f[i][st][j] += f[i - 1][st2][j - c(st)];
}
}
}
}
}
for (int st = 0; st < (1 << n);st++)
ans += f[n - 1][st][k];
cout << ans << nl;
}
边栏推荐
猜你喜欢
随机推荐
如何利用PHP实现词法分析器与自定义语言
2022年值得尝试的7个MQTT客户端工具
WWW'22 推荐系统论文之多任务与对比学习篇
tiup mirror sign
tiup mirror publish
Qt | 控件之 QComboBox
性能测试详解(理论篇)
关于小程序TabBar跳转页面跟TabBar标签栏的icon不对应的分析(debug)
ROS人机交互软件
VPP snort插件
tiup mirror modify
Alibaba "MySQL Growth Manual" Lite Edition
Qt | 关于如何使用事件过滤器 eventFilter
推荐系统相关顶会整理
MySQL【数据类型】
已经2022下半年了,居然还在说链动2+1!
CS5210的参数详情资料分享
CWE4.8:2022年危害最大的25种软件安全问题
DC-DC选型及电路设计
MPLS实验









