//首先这道题目真的是好题,但是POJ太坑了,给的n和m的范围偏小了,一直WA,很无奈。
题目大意:给你一张n*m的草坪,每一块如果是1就表示可以放东西,0就不可以,你不可以在相邻的草上面放东西,问你最多能放几个;
题目解析:开始dp肯定从这一行上面的草坪开始转移,肯定要状态压缩,否则肯定超时并且不能记忆化搜索,有个小技巧,如果一个排列有两个相邻的肯定不可以,所以我们先判断x&(1<<x),如果不为0就表示有两个是相邻的,应该排除,把可以的存在sta[i]中,dp的时候枚举一下序列如果和上面的序列符合题意的话只要(x&y)==0;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define mod 1000000000;
using namespace std;
int main()
{
int n,m,i,j,k,l,number,grass[20],dp[20][5010],temp,sta[5010],sum;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(grass,0,sizeof(grass));
memset(dp,0,sizeof(dp));
memset(sta,0,sizeof(sta));
number=0;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&temp);
if(temp==1)
grass[i]|=1<<j;
}
}
k=0;
for(i=0;i<(1<<m);i++)
{
if((i&(i<<1))==0)
sta[++k]=i;
}
for(i=1;i<=k;i++)
{
if((grass[0]|sta[i])==grass[0])
dp[0][sta[i]]=1;
}
for(i=1;i<n;i++)
{
for(j=1;j<=k;j++)
{
if((sta[j]|grass[i])!=grass[i])
continue;
for(l=1;l<=k;l++)
{
if((sta[l]|grass[i-1])!=grass[i-1])
continue;
if((sta[l]&sta[j])==0)
dp[i][sta[j]]=dp[i][sta[j]]+dp[i-1][sta[l]]%mod;
}
}
}
sum=0;
for(i=1;i<=k;i++)
{
sum+=dp[n-1][sta[i]];
sum%=mod;
}
printf("%d\n",sum);
}
return 0;
}