【学术篇】状态压缩动态规划——POJ3254/洛谷1879 玉米田Corn Field
2017-03-26 19:04
260 查看
我要开状压dp的坑了。。直播从入门到放弃系列。。
那就先拿一道状压dp的水题练练手吧。。
然后就找到了这一道。。这道题使我清醒地认识到阻碍我的不是算法,而是视力= =
传送门:
poj:http://poj.org/problem?id=3254
luogu:https://www.luogu.org/problem/show?pid=1879.233333 (雾
我们可以看出,我们可以通过i-1行的放法转移出第i行的放法,所以这题是dp无疑。状态转移方程:
然而j是一种状态而不是一个数字。所以这就是本题不同于传统dp的地方,我们要状压
嗯,状压,什么是状压? 状态压缩
那什么是状态压缩?
以本题为例,我们发现n,m的范围很小(其实有一维的范围很小就可以O(∩_∩)O)
而每一个格子上都只有放牛和不放牛两种选择,所以……
既然是学信息的,我们可以用二进制来表示啊~
我们可以用不超过12位二进制来表示当前行中的状态,从而完成了压缩。。 还有可爱的位运算为伴哦~
大体来说就是这样。。
对于行之间相邻的情况,把两行按位与一下即可。。
这个放心即可。。我们可以先预处理。。然后发现可枚举的状态其实是十分有限的..
预处理大概是长介个样纸:
经实测,在2^12=4096个状态中,能在1行中合法存在的只有377个。。(要算错了可以来纠正我_ (:з」∠) _反正我日常算错。。不过算错应该不会差多少)
总之不会爆炸,而且还跑得很快就对了~~
啰嗦了半天,还是上代码吧。。
大概就这样吧。。
文末彩蛋
为什么我说这题卡视力了呢?
因为我前几遍硬是没看见[b]取模~[/b]
还到luogu下了一次数据才看出来。。
我多半是完了_ (:з」∠) _
那就先拿一道状压dp的水题练练手吧。。
然后就找到了这一道。。这道题使我清醒地认识到阻碍我的不是算法,而是视力= =
传送门:
poj:http://poj.org/problem?id=3254
luogu:https://www.luogu.org/problem/show?pid=1879.233333 (雾
题目大意:
n*m的01矩阵上放棋子(牛),不能放到相邻格子,问方案数。(啥也不放算一种方案(然而我视力好到看到这一点了))题目分析:
都说了状压dp 水题,肯定要用仙人图上在线分支定界启发式带花树上下界最小费用流解决问题啊~(什么鬼)我们可以看出,我们可以通过i-1行的放法转移出第i行的放法,所以这题是dp无疑。状态转移方程:
第i行状态为j(j合法): f[i][j]=sigma(f[i-1][k]) (k与j不冲突)
然而j是一种状态而不是一个数字。所以这就是本题不同于传统dp的地方,我们要状压
嗯,状压,什么是状压? 状态压缩
那什么是状态压缩?
以本题为例,我们发现n,m的范围很小(其实有一维的范围很小就可以O(∩_∩)O)
而每一个格子上都只有放牛和不放牛两种选择,所以……
既然是学信息的,我们可以用二进制来表示啊~
我们可以用不超过12位二进制来表示当前行中的状态,从而完成了压缩。。 还有可爱的位运算为伴哦~
大体来说就是这样。。
如何筛选合法状态?
题目中,对于同一行中相邻的情况,我们可以用(i&(i-1))解决..对于行之间相邻的情况,把两行按位与一下即可。。
每一行枚举复杂度不会爆炸吗?
(本题不存在此担心,2^12^2勉强能跑过,但有些题是30左右就hold不住了..)这个放心即可。。我们可以先预处理。。然后发现可枚举的状态其实是十分有限的..
预处理大概是长介个样纸:
for(int i=0;i<1<<m;i++) if(!(i&(i<<1))){ op[cnt++]=i; }
经实测,在2^12=4096个状态中,能在1行中合法存在的只有377个。。(要算错了可以来纠正我_ (:з」∠) _反正我日常算错。。不过算错应该不会差多少)
总之不会爆炸,而且还跑得很快就对了~~
啰嗦了半天,还是上代码吧。。
代码实现
#include <cstdio> #include <cstring> int op[380],cnt,n,m,ans; int f[13][380],za[13]; void dp(){ for(int i=0;i<1<<m;i++) if(!(i&(i<<1))){ op[cnt]=i; if(!(i&za[0])) f[0][cnt]=1; cnt++; } for(int i=1;i<n;i++) for(int j=0;j<cnt;j++){ if(op[j]&za[i]) continue; for(int k=0;k<cnt;k++) if(!(op[j]&op[k])) f[i][j]+=f[i-1][k]; } } int main(){ scanf("%d%d",&n,&m); ans=0; cnt=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ int k; scanf("%d",&k); if(!k) za[i]|=(1<<j); }dp(); for(int i=0;i<cnt;i++) ans=(ans+f[n-1][i])%100000000; printf("%d\n",ans); }
大概就这样吧。。
文末彩蛋
为什么我说这题卡视力了呢?
因为我前几遍硬是没看见[b]取模~[/b]
还到luogu下了一次数据才看出来。。
我多半是完了_ (:з」∠) _
相关文章推荐
- 洛谷 1052 dp 状态压缩
- Codevs_P1358 棋盘游戏(状态压缩动态规划)
- Vijos 1921 严厉的班长 【状态压缩动态规划】
- POJ-1185 炮兵阵地 动态规划+状态压缩
- 洛谷 1052 dp 状态压缩
- 《挑战程序设计竞赛》3.4.1 动态规划-状态压缩DP POJ3311 2686 2411 2441 3254 2836 1795 3411(2)
- Vijos 1921 严厉的班长 【状态压缩动态规划】
- 【jzoj5251】【GDOI2018模拟8.11】【决战】【状态压缩动态规划】
- BZOJ 1948 CEOI 2006 Connect 状态压缩动态规划
- Poj 2923 Relocation(状态压缩+动态规划)
- CodeForce 706C 动态规划 利用下标表示状态 递推 (伪状态压缩)
- 洛谷 1052 dp 状态压缩
- hihocoder 1044 动态规划 状态压缩
- POJ_2663_Tri Tiling_DFS,状态压缩,动态规划
- 洛谷 P2157 [SDOI2009]学校食堂Dining【状态压缩】
- 状态压缩动态规划
- [ACM_动态规划] 轮廓线动态规划——铺放骨牌(状态压缩1)
- BZOJ_P1072 [SCOI2007]排列perm(状态压缩动态规划)
- 状态压缩动态规划总结
- BZOJ_P4416 [SHOI2013]阶乘字符串(状态压缩动态规划)