欢迎来到SamXia的博客|

SamXia

园龄:1个月粉丝:1关注:2

2025-01-31 11:54阅读: 17评论: 0推荐: 0

dp深入与进阶(3):状压dp(2025.02.03)

01.状压dp概念:

通过将状态压缩为整数(二进制数),从而优化状态转移的方法即为状压dp

而实际使用和操作时可以考虑位运算,还可以在一定程度上加快程序运行

优点:

1.简化复杂状态:用二进制压缩表示复杂状态,如 TSP 问题里城市访问状态

2.降低空间开销:相比传统记录方式,大幅减少状态存储的空间。

3.提升时间效率:利用位运算快速操作状态,减少计算量。

4.应用广泛:适用于棋盘布局、资源分配等多领域问题。

5.实现简便:基于二进制运算与 DP 框架,代码易理解与调试。

(以上内容出自豆包)

02.状压dp的实现:Luogu P1896 [互不侵犯]

i.状态压缩

我们以行为单位,对于每一行放/不放王的状态,压缩为二进制01串

0 该位置不放王

1该位置放王

例:

对于上图,有状态s=(101001000)2=328

如此便可以用二进制数来存储所有的状态

ii.条件判断

Q:

对于每次个王,

满足上、下、左、右、左上、左下、右上、右下八个方向上相邻的格子都不能有相邻的王

如何进行这样的判断呢?

A:

我们假设第i行状态为s1,而前一行的状态为s2

1.因为单行内左右不可为王,即要满足((s1<<1)&s1==0)&&((s1>>1)&s1==0) 简写!((s1<<1)|(s1>>1)&s1)

2.而相邻行不能为有距离大于2的位置为王,即((s1<<1)&s2==0)&&(s1&s2==0)&&((s1>>1)&s2==0) 简写!((s1<<1)|s1|(s1>>1)&s2)

可以把判断满足条件的语句封装为函数sta(s1,s2),满足条件返回1,不满足返回0,便于调用

iii.状态转移

(1)状态设计:

考虑f[i][num][s]表示第i行,使用num个棋子,当前状态为s的可行方案数

其中满足s1为本行(第i行)的状态,s2为上一行的状态

(2)公式推导:

对于所有满足条件的s1,s2,所有s2的方法数s1都满足

f(i,num,s1)=sta(s1,s2)f(i1,numgetnum(s1),s2)

其中getnum(s1)函数用来统计s1中数字1的个数

初始化:f(0,0,0)=1,第00个棋子状态为0的方案为1

iv.代码实现

#include<bits/stdc++.h>
using namespace std;
long long f[10][100][2010];
//判断s1,s2是否满足条件
bool sta(int s1,int s2)
{
if(((s1<<1)|(s1>>1))&s1)
return 0;
if(((s2<<1)|(s2>>1))&s2)
return 0;
if(((s1<<1)|s1|(s1>>1))&s2)
return 0;
return 1;
}
//计算s二进制中有多少个1
int get_num(int s)
{
int ret=0;
while(s)
{
ret+=(s&1);//取二进制最后一位的1加入ret
s>>=1;//s右移一位
}
return ret;
}
int main()
{
int n,k;
cin>>n>>k;
f[0][0][0]=1;
int maxn=1<<n;
for(int i=1;i<=n;++i)//枚举当前行i
for(int s1=0;s1<maxn;++s1)//枚举本行状态s1
for(int s2=0;s2<maxn;++s2)//枚举上一行状态s2
{
if(sta(s1,s2)==0)
continue;
for(int num=0;num<=k;++num)//枚举放了的棋子数
{
int num_s1=get_num(s1);
if(num-num_s1>=0)//判断是否可以进行dp
f[i][num][s1]+=f[i-1][num-num_s1][s2];
}
}
long long ans=0;
for(int i=0;i<maxn;++i)
ans+=f[n][k][i];
cout<<ans;
return 0;
}
//这个题有更优化的思路 需要进行预处理 感兴趣的可以看XichenOC的题解
//代码:SamXia

这个题有另一个题解XiChenOC-状压DP(学习笔记)

来自XiChenOC大佬,里面有本题的优化技巧,可以进行学习理解

本文作者:SamXia

本文链接:https://www.cnblogs.com/SamXia/p/18695695

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   SamXia  阅读(17)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起