Corn fields poj 3254 (状压dp入门)

来源:互联网 发布:搭建改号voip linux 编辑:程序博客网 时间:2024/05/23 18:34

状态压缩动态规划:
   动态规划的状态有时候比较恶心,不容易表示出来,需要用一些编码技术,把状态压缩的用简单的方式表示出来。
典型方式:当需要表示一个集合有哪些元素时,往往利用2进制用一个整数表示。


再普及一下位运算:

& 按位与      如果两个相应的二进制位都为1,则该位的               结果值为1,否则为0
| 按位或      两个相应的二进制位中只要有一个为1,该位              的结果值为1
^ 按位异或    若参加运算的两个二进制位值相同则为0,               否则为1
~ 取反        ~是一元运算符,用来对一个二进制数按位取        反,即将0变1,将1变0
<< 左移       用来将一个数的各二进制位全部左移N位,        右补0
>> 右移       将一个数的各二进制位右移N位,移到右端        的低位被舍弃,对于无符号数,高位补0

好吧,回到这题

这道题也就是俗称的牛吃草问题,【题目大意】一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛(不包括斜着的),即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)
【Input】1<=n<=12,1<=m<=12
【Output】一个mod100000000的整数
一看到如此小的数据范围,又是求方案数,自然而然就联想到了状态压缩的DP。

话不多说,上代码:

#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int maxn = 100010;int dp[20][maxn];int st[maxn];int maps[maxn];int judge1(int x){//这里原理是判断当前状态是否存在两个1相邻,根据&的性质,只有两个都为1才返回1return x&(x<<1);}int judge2(int x,int y){//判断是否可以将这个状态放到地图上return (maps[x] & st[y]);}int main(){int i,j,k,m,n;int x,y,z;while(scanf("%d%d",&m,&n)!=EOF){memset(maps,0,sizeof(maps));memset(dp,0,sizeof(dp));memset(st,0,sizeof(st));for(i=1;i<=m;i++){for(j=1;j<=n;j++){scanf("%d",&x);if(!x) maps[i] += (1<<j-1);}}int cnt = 0;for(i=0;i<(1<<n);i++){if(!judge1(i)){//不停地去除没用的状态st[++cnt] = i;}}for(i=1;i<=cnt;i++){if(!judge2(1,i)){dp[1][i] = 1;}}for(i=2;i<=m;i++){for(j=1;j<=cnt;j++){if(judge2(i,j))continue;//枚举这一层可能存在的状态for(k=1;k<=cnt;k++){if(!judge2(i-1,k)){//枚举上一层存在的状态if(!(st[k]&st[j]))判断上下相邻是否可放dp[i][j]+=dp[i-1][k];//状态转移}}}}int ans=0;for(i=1;i<=cnt;i++){ans=(ans+dp[m][i]%100000000)%100000000;}printf("%d\n",ans%100000000);}return 0;} 


1 0
原创粉丝点击