分析:
给出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[n][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();
}
}