动态规划:状压DP

时间:2023-03-09 17:49:21
动态规划:状压DP

状压DP可以用在NP问题的小规模求解中(不理解,感觉和可以搜索的题很类似)

如果状态是个网格,数据范围很小,基本锁定状压DP

例题是BZOJ1725

题意是这样的,给定一个黑白图,然后种田,要求田与田之间不能挨着

而且只能往黑格子上种田

这个的意思让我联想到了棋盘动规的骑士游历和过河卒

或者是完全背包里的货币系统

扯远了,我把我对代码的理解都写在了注释里面

 #include<cstdio>
#include<algorithm>
using namespace std;
const int mod=;
const int maxn=;
int m,n,ans;
int mp[maxn],f[maxn][<<maxn];
void dp()
{
//--------->>>>>>>>这么个方向
int ed=(<<n)-; //每一列的状态总数
for(int i=;i<=ed;i++)
{
if((i&(i>>))==&&(i|mp[])==mp[]) //初始化第一列的方案数
//看是否是1010101这样的状态
//然后看这个状态如果和mp的描述相符,就给i安排上
f[][i]=;
}
for(int i=;i<=m;i++)
for(int j=;j<=ed;j++)
if(f[i-][j]) //如果上一个阶段的此种状态有值
for(int k=;k<=ed;k++)
if((j&k)==&&(k|mp[i])==mp[i]&&(k&(k>>))==)
//那么本阶段的一些状态就要被安排上
//首先状态重复的不行
//然后必须得跟地图描述一致
//然后还得是10101这样的
//吐槽一下,状态压缩真滴玄学
f[i][k]=(f[i][k]+f[i-][j])%mod;
//可以愉快地继承了
for(int i=;i<=ed;i++)
ans=(ans+f[m][i])%mod; //把最终迭代的结果加在一起就是最终结果了
}
int main()
{
int x;
scanf("%d%d",&m,&n);
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)
{
scanf("%d",&x);
mp[i]<<=;mp[i]+=x;
//mp直接通过输入的0和1处理成二进制数,骚操作
//mp存的就是每一列的地图情况
}
dp();
printf("%d",ans);
return ;
}

当然这是谁我的理解,水平有限目前仅仅是这个程度,日后还要大量刷dp题才好的