您的位置:首页 > 其它

状压DP——Corn Fields ( POJ 3254 )

2016-08-07 16:10 267 查看
题目链接:

http://poj.org/problem?id=3254

分析:

给出M行,N列的土地,1代表肥沃,0代表贫瘠,只能再肥沃的土地上种玉米并且不能相邻着种,问有多少中种植的方法。

题解:

1.这是一道状压DP的入门题,我们首先用一个一维数组记录每一个行肥沃徒弟的状态,把它记录为一个二进制数

for(int i=1;i<=n;i++)
{
Map[i] = 0;
for(int j=1;j<=m;j++)
{
int k;
scanf("%d", &k);
Map[i] = (Map[i]<<1)+k;//记录为二进制数
}
}


2.设dp[i][j]为在第i行种植j状态的玉米有多少种情况,

那么枚举状态k我们可以得出dp[i][j]+= dp[i-1][k];不过这里有一个前提,种植j个和k个在那一行是合法的并且这两行种植的玉米不会上下相邻。

判断上下两行是否由相邻:

可以异或这两个值,如果为0则说明可行

判断种植j状态的玉米在第i行是否可行:

可以异或这一行的肥沃土地和j,如果结果和j相等则说明可行

判断种植j状态的玉米再第i行是否会相邻:

在j后加一个0即将j左移一位,然后再与它本身异或如果结果不为0则说明由相邻情况。

int check(int x,int y)
{
if((Map[x]&y)!=y)//判断y这种状态的放置方式是否合法
return 0;
if((y&(y<<1))!=0)
return 0;
return 1;
}


参考代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define mod 100000000
int n,m,a[15];
int dp[13][1<<13];
int judge(int x,int y)
{
if((a[x]&y)!=y)//判断y这种状态的放置方式是否合法
return 0;
if((y&(y<<1))!=0)
return 0;
return 1;
}
void work()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=n;i++)//枚举所有行
{
for(int j=0;j<(1<<m);j++)//枚举这一行的所有可能存在的状态
{
if(judge(i,j)==0)//判断在第i行放置j这种状态的牛是否合法。
continue;
for(int k=0;k<(1<<m);k++)
{
if((j&k)!=0)continue;//j和k不能有上下相邻的部分
dp[i][j]=dp[i][j]+dp[i-1][k];
dp[i][j]%=mod;
}
}
}
int output=0;
for(int i=0;i<(1<<m);i++)
{
output+=dp
[i];
output%=mod;
}
printf("%d\n",output);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
{
a[i]=0;
for(int j=1;j<=m;j++)
{
int k;
scanf("%d",&k);
a[i]=(a[i]<<1)+k;//状态压缩为一个二进制的值。
}
}
work();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  状压DP ACM