题目大意:
给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法。
基本思路:
首先得一行一行的来,然后这里如果每次都挨个试每种状态的话绝对超时,然后就是把所以满足两两不相邻的情况找出来存起来,每次每一行拿这个去判断,这样 每一行内相邻的情况找出来的,下面的dp就是找满足都放在肥沃土壤和相邻行没有相邻的情况,这样问题就得到了解决,然后这个状态转移方程就得到了,dp【i】【j】就是第i行状态为j时候的种类数量,因为这个最多有 1<<12,不超过50000还是可以的,至此问题得到圆满解决;
代码如下:
#include<iostream>
#include<iomanip>
#include<string>
#include<queue>
#include<map>
#include<list>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
const int mod = 100000000;
const int maxn = 5000+10;
int st[maxn];//用来放一行中彼此不相邻的可能的情况总数,可以在一定程度上剪枝;
int gra[maxn];//用来存放每一行的是否肥沃情况;
int dp[15][maxn];
bool judge1(int x)//用来判断某种状态是否符合提议,任何两只牛不相邻
{
return !(x&(x<<1));
}
bool judge2(int i,int x)//是否都放在肥沃的地方;
{
return ((gra[i]|x)==gra[i]);
}
bool judge3(int x,int y)
{
return st[x]&st[y];
}
int main()
{
memset(dp,0,sizeof(dp));
memset(st,0,sizeof(st));
memset(gra,0,sizeof(gra));
int n,m;
scanf("%d%d",&n,&m);
int mm=1<<m,cnt=0;
for(int j=0;j<mm;j++)//先找出所有符合两两不相邻的情况;
if(judge1(j)) st[cnt++]=j;
int t;
for(int i=1;i<=n;i++)
{
for(int j=m-1;j>=0;j--)
{
scanf("%d",&t);
gra[i]+=(t<<j);
}
}
for(int j=0;j<cnt;j++)
if(judge2(1,st[j])) dp[1][j]=1;
for(int i=2;i<=n;i++)
{
for(int j=0;j<cnt;j++)
{
if(!judge2(i,st[j])) continue;
for(int k=0;k<cnt;k++)
{
if(!judge2(i-1,st[k])) continue;//这是剪枝,先找出能符合i-1行情况的放法,这里不用考虑第i-2行的情况,因为不行的情况是0,加了也相当于没加;
if(!judge3(j,k)) dp[i][j]+=dp[i-1][k];
}
}
}
int sum=0;
for(int j=0;j<cnt;j++)
sum=(sum+dp[n][j])%mod;
printf("%d\n",sum);
return 0;
}