Corn Fields poj3254
来源:互联网 发布:股票牛人 知乎 编辑:程序博客网 时间:2024/06/18 05:31
题意:给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法。
分析:假如我们知道第 i-1 行的所有的可以放的情况,那么对于第 i 行的可以放的一种情况,我们只要判断它和 i - 1 行的所有情况的能不能满足题目的所有牛不相邻,如果有种中满足,那么对于 i 行的这一中情况有 x 中放法。
前面分析可知满足子状态,我们我们确定可以用dp来解决。
但是我们又发现,状态是一种放法,不是我们平常dp的简单的状态,所以要用状态压缩!
但是什么是状态压缩呢?
比如前面的情况,一种放法是最多由12个 0 或者 1 组成的,那么我们很容易想到用二进制,用二进制的一个数来表示一种放法。
定义状态dp【i】【j】,第 i 行状态为 j 的时候放牛的种数。j 的话我们转化成二进制,从低位到高位依次 1 表示放牛0表示没有放牛,就可以表示一行所有的情况。
那么转移方程 dp【i】【j】=sum(dp【i-1】【k】)
状态压缩dp关键是处理好位运算。
这个题目用到了 & 这个运算符。
用 x & (x<<1)来判断一个数相邻两位是不是同时为1,假如同时为 1 则返回一个值,否则返回 0 ,这样就能优化掉一些状态
用 x & y 的布尔值来判断相同为是不是同时为1。
解法一:状压dp、
#include<iostream>#include<cstdio>using namespace std;const int p=100000000;int n,m,a[1<<14],st[1<<14],dp[14][1<<14];bool judge1(int x){return x&(x<<1);}bool judge2(int i,int x){return a[i]&st[x];}int main(){int i,j,k=0,f,x,ans=0;scanf("%d%d",&n,&m);for(i=0;i<n;i++){for(j=0;j<m;j++){scanf("%d",&x);if(!x){a[i]+=(1<<j);}}}for(i=0;i<(1<<m);i++){if(!judge1(i)){st[k++]=i;}}for(i=0;i<k;i++){if(!judge2(0,i)){dp[0][i]=1;}}for(i=1;i<n;i++){for(j=0;j<k;j++){if(judge2(i,j)) continue;for(f=0;f<k;f++){if(judge2(i-1,f)) continue;if(!(st[f]&st[j])){dp[i][j]+=dp[i-1][f];}}}}for(i=0;i<k;i++){ans+=dp[n-1][i];ans%=p;}printf("%d\n",ans);return 0;}
解法二:搜索。
#include<iostream>#include<cstring>#include<cstdlib>#include<cmath>#include<cstdio>using namespace std;const int maxn=(1<<16);int m,n;int ans=0;int mod=100000000;int f[30][maxn],a[30];void dfs(int i,int j,int state,int nex)//state表示当前行状态,{//nex表示下一行状态 if(j>=n) { f[i+1][nex]+=f[i][state]; f[i+1][nex]%=mod;//这个要取余,防止中间过程溢出. return; } dfs(i,j+1,state,nex);//这一个点不放 if(!((1<<j)&state)) dfs(i,j+2,state,nex|(1<<j));//这一个点如果能放就放 return;}int main(){ scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) for(int j=0;j<n;j++) { int x; scanf("%d",&x); if(x==0) a[i]=a[i]|(1<<j); } f[1][a[1]]=1;//当第一行什么也不放时只有一种方法 for(int i=1;i<=m;i++) for(int j=a[i];j<(1<<n);j++)//这儿从a[i]开始就行了{//因为放0个就是a[i],没有比它更少了. if(f[i][j]) dfs(i,0,j,a[i+1]); } for(int i=0;i<(1<<n);i++) {if(f[m+1][i]){ans+=f[m+1][i];ans%=mod;}}//注意最后加的是m+1行. printf("%d",ans); return 0;}
阅读全文
0 0
- 【DP】 poj3254 Corn Fields
- DP poj3254 Corn Fields
- poj3254 Corn Fields
- POJ3254--Corn Fields
- poj3254 Corn Fields
- POJ3254--Corn Fields
- 【状压】Corn Fields POJ3254
- POJ3254 Corn Fields
- [POJ3254] Corn Fields
- 【POJ3254】Corn Fields
- POJ3254 Corn Fields
- poj3254 Corn Fields
- POJ3254--Corn Fields
- poj3254 Corn Fields
- poj3254 Corn Fields
- POJ3254 Corn Fields
- POJ3254 Corn Fields
- POJ3254:Corn Fields
- gitlab安装-配置-运维
- 字符串操作,翻转句子中单词的顺序--经典面试题两种解法
- 红黑树Red-Black tree初步详解(Java代码实现)
- leetcode[Path Sum III]//待整理多种解法
- Android DataBinding使用详解(一)
- Corn Fields poj3254
- C++面试中String类的一种写法
- 使用Python和OpenCV检测图像中的物体并将物体裁剪下来
- HDU2586 How far away? —— 倍增LCA
- Linux命令top单个进程内存翻译
- git操作手册
- AndroidStudio关于项目构建
- 逗号分隔字符串转List<Long>
- ACdream 1078 Cutting Figure (dfs)