我要开状压dp的坑了。。直播从入门到放弃系列。。

那就先拿一道状压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);
}

大概就这样吧。。

文末彩蛋
为什么我说这题卡视力了呢?
因为我前几遍硬是没看见取模~
还到luogu下了一次数据才看出来。。
我多半是完了_ (:з」∠) _

最新文章

  1. 手机app软件开发有什么需要注意的细节?
  2. xcode8.2 打包问题
  3. 【其他】win7创建wifi热点共享给手机使用
  4. Code First 关系 Fluent API
  5. 自定义Listview
  6. Appium+Robotframework实现Android应用的自动化测试-1:Appium在Windows中的安装
  7. NOIP 2015 信息传递
  8. cordova 开发属于自己的插件---android
  9. ps做gif love教程(转)
  10. Codeforces Beta Round #85 (Div. 1 Only) A. Petya and Inequiations 贪心
  11. and or判别
  12. StringBuilder字符串拼接类
  13. uboot内存分布
  14. JavaScript简单入门(补充篇)
  15. [国嵌笔记][021-022][ARM处理器工作模式]
  16. Linux命令:let
  17. selenium java 浏览器操作
  18. 使用json web token
  19. Java基础之Java 修饰符
  20. SpringCloud调用服务示例

热门文章

  1. Noip 2012 day2t1 同余方程
  2. NX二次开发-NXOpen窗口打印NXMessageBox&amp;ListingWindow
  3. (转)Java 标注(Annotation)详解
  4. ThreadPoolTaskExecutor的配置使用
  5. python语法基础(类)
  6. ionic js 滑动框ion-slide-box 滑动框是一个包含多页容器的组件,每页滑动或拖动切换
  7. List&lt;&gt; ,string[]和string的相互转换
  8. META标签的定义与使用(一、HTTP标题信息(http-equiv))
  9. Leetcode973. K Closest Points to Origin最接近原点的K个点
  10. erlang 开发建议