您的位置:首页 > 其它

poj 3254 Corn Fields (状压DP)

2015-10-07 11:16 351 查看
题目大意: N*M的农场, 有的格子可以放牛,有的不行。在这块地方放牛,相邻的格子不能有牛。求方案数。

N、M都比较小(<13),那么可以用1个2进制位表示一行中的每一个格子的状态,0表示不放牛,1表示放牛,一行中的所有二进制位构成一个状态s。

设dp[i][s]表示第i行状态为s时的方案数。那么状态转移方程:dp[i][s]=∑(dp[i−1][s′])

其中s’为i-1行的状态,且满足s和s’相同位不同时为1。

注意在枚举某一行i的状态的时候,有的状态是不合法的,可以通过奇妙的位运算来判别这些不合法的状态。比如判断状态s中是否存在两个相邻的1,判定s&(s>>1)是否为1即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef __int64 LL;
#define mod 100000000
#define maxn 1<<12

LL dp[12][maxn];
int cur[12];

inline bool check1(int i,int s)
{
if((cur[i]&s)!=s) return 0;
if(s&(s>>1)) return 0;
return 1;
}

inline bool check2(int s1,int s2)
{
if(s1&s2) return 0;
return 1;
}

int main()
{
int n,m,i,j,k,a,M;
while(~scanf("%d%d",&n,&m)){
memset(dp,0,sizeof(dp));
M=(1<<m);
for(i=0;i<n;++i){
cur[i]=0;
for(j=0;j<m;++j)
{
scanf("%d",&a);
cur[i]=(cur[i]<<1)+a;
}
}
for(j=0;j<M;++j) if(check1(0,j)) ++dp[0][j];
for(i=1;i<n;++i)
for(j=0;j<M;++j)
{
if(!check1(i,j)) continue;
for(k=0;k<M;++k)
{
if(!check2(j,k)) continue;
dp[i][j]+=dp[i-1][k];
if(dp[i][j]>mod) dp[i][j]-=mod;
}
}
LL ans=0;
for(i=0;i<M;++i) ans=(ans+dp[n-1][i])%mod;
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp