状压DP可以用在NP问题的小规模求解中(不理解,感觉和可以搜索的题很类似)
如果状态是个网格,数据范围很小,基本锁定状压DP
例题是BZOJ1725
题意是这样的,给定一个黑白图,然后种田,要求田与田之间不能挨着
而且只能往黑格子上种田
这个的意思让我联想到了棋盘动规的骑士游历和过河卒
或者是完全背包里的货币系统
扯远了,我把我对代码的理解都写在了注释里面
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int mod=100000000; 5 const int maxn=15; 6 int m,n,ans; 7 int mp[maxn],f[maxn][1<<maxn]; 8 void dp() 9 { 10 //--------->>>>>>>>这么个方向 11 int ed=(1<<n)-1; //每一列的状态总数 12 for(int i=0;i<=ed;i++) 13 { 14 if((i&(i>>1))==0&&(i|mp[1])==mp[1]) //初始化第一列的方案数 15 //看是否是1010101这样的状态 16 //然后看这个状态如果和mp的描述相符,就给i安排上 17 f[1][i]=1; 18 } 19 for(int i=2;i<=m;i++) 20 for(int j=0;j<=ed;j++) 21 if(f[i-1][j]) //如果上一个阶段的此种状态有值 22 for(int k=0;k<=ed;k++) 23 if((j&k)==0&&(k|mp[i])==mp[i]&&(k&(k>>1))==0) 24 //那么本阶段的一些状态就要被安排上 25 //首先状态重复的不行 26 //然后必须得跟地图描述一致 27 //然后还得是10101这样的 28 //吐槽一下,状态压缩真滴玄学 29 f[i][k]=(f[i][k]+f[i-1][j])%mod; 30 //可以愉快地继承了 31 for(int i=0;i<=ed;i++) 32 ans=(ans+f[m][i])%mod; //把最终迭代的结果加在一起就是最终结果了 33 } 34 int main() 35 { 36 int x; 37 scanf("%d%d",&m,&n); 38 for(int i=1;i<=m;i++) 39 for(int j=1;j<=n;j++) 40 { 41 scanf("%d",&x); 42 mp[i]<<=1;mp[i]+=x; 43 //mp直接通过输入的0和1处理成二进制数,骚操作 44 //mp存的就是每一列的地图情况 45 } 46 dp(); 47 printf("%d",ans); 48 return 0; 49 }
当然这是谁我的理解,水平有限目前仅仅是这个程度,日后还要大量刷dp题才好的