状压DP,全程状态压缩动态规划
核心便是状态压缩。。。。。
状态压缩简介
状态压缩,是利用计算机二进制的性质来描述状态的一种DP方式,经常与BFS和DP连用
举个不恰当的栗子
有一个n层楼的楼房,每一层可以选择开窗户或者不开窗户
令n=6
有二进制数101101,每一位表示这一层楼是否开了窗户,1 表示开了,0表示没开,我们就能利用位运算快速地得知1,3,4,6层楼开了窗
所以说状态压缩可以说得上是用位运算优化后的暴力
状压DP简介
状态压缩+动态规划=状压DP
例题
P1879[USACO06NOV]玉米田Corn Fields
原题链接
https://www.luogu.org/problem/P1879
读入以后,用f[i]来表示第i行上草地的情况,f[]是boolean
我们需要在0~max_state-1里找到合法状态(max_state代表这道题的最大状态)判断方法就是吧这个二进制数左移一位,然后右移一位。若这个状态是合法的,就return 0
然后开始DP,从第一行开始,在每行里面罩所欲的状态,若这个状态是合法的,且不在不适合种草的草地上面,那么接下来开始找一行合法的情况,吧上一行的情况加到f[i][j]里
最后吧末尾行的情况数全部加起来就是答案了
#include <cstdio>
#include <iostream>
const int maxn=4096,mod=100000001;
int n,m;
int tmap[19][19];
int dmap[19];
int dp[19][maxn];
bool can[maxn];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>tmap[i][j];
map[i]=(map[i]<<1)+tmap[i][j];
}
}
int maxstate=(1<<m)-1;
for(int i=0;i<=maxstate;i++)
if((((i<<1) and i)==0) and (((i>>1) and i)==0))
can[i]=true;
for(int i=0;i<=maxstate;i++)
if(can[i] and ((i and dmap[1])==i))
dp[1][i]=1;//先预处理处第一行(对于某一行的状态,只受上一行的影响)
for(int i=2;i<=n;i++)
for(int j=0;j<=maxstate;j++)
if(can[j] and (j and dmap[i])==j)
for(int k=0;k<=maxstate;k++)
if(k and j==0)
dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;//DP
long long ans=0;
for(int i=0;i<=maxstate;i++)
ans=(ans+dp[n][i])%mod;//答案在最后一行
}
JZOJ1236邦德I
#include <cstdio>
#include <iostream>
using namespace std;
double a[20][20];
int b[20],c[20];
double f[2500001];
int max(int x, int y)
{
return x>y?x:y;
}
int power(int x, int y)
{
int ans=1;
for(int i=1;i<=y;i++)
ans*=x;
return ans;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
a[i][j]/=100;
}
f[0]=100;
for(int i=1;i<=power(2,n+1)-1;i++)
{
int t=0;
for(int j=1;j<=n;j++)
if(i and b[j]!=0)
{
t+=1;
c[t]=j;
}
for(int j=1;j<=t;j++)
f[i]=max(f[i=b[c[j]]]*a[c[j]][t],f[i]);
}
cout<<f[power(2,n+1)-1];
return 0;
}
本文介绍了状态压缩的概念,它是通过二进制位运算优化动态规划的一种方法。以一个n层楼开窗户的问题为例,说明如何用二进制表示状态,并应用于动态规划。接着讲解了如何结合动态规划形成状压DP,并给出了USACO06NOV的玉米田问题作为例题,解释了如何运用状压DP求解问题。

988

被折叠的 条评论
为什么被折叠?



