数据大小已经很明显的提示,这题是状压DP啊!
读入以后,我们用F[i]来表示第i行上的草地情况,这里F数组里的是二进制数。MAXSTATE是2n,也就是这道题的最大状态(n列都是1)。
然后我们在0~MAXSTATE-1这些状态里找到合法状态,也就是不能两头牛的草地是相邻的。判断方法就是把这个二进制数左移一位and,然后右移一位and。如果这个状态是合法的,那么都应该返回0。
然后就开始动规,从第一行开始,在每行里找所有状态,如果这个状态是合法的,且不会在贫瘠的草地上(和(j & F[i]) == j说明没有草地种在贫瘠的地方),那么接下来开始找上一行的合法情况(上下两行之间没有相邻的草地),把上一行的情况数加到f[i][j]里。
最后把最下面一行的每一列的情况书统统加起来,就是答案啦~
#include <cstdio>
#define maxn 100000000
#define size 4096
using namespace std;
int m,n,c[13][13],f[13],dp[13][size];
bool pd[size];
/*
m n 表示 牧场的高和宽
c[i][j] 表示 i行j列的位置 是否可以放草,1为可放,0为不可
f[i] 表示 第i行的草地 状态
dp[i][j] 表示 第i行,状态为j,一共有多少方案
pd[i]表示 草地按照i这样的状态摆放,是否会有左右冲突
*/
int main(){
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
scanf("%d",&c[i][j]);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
f[i]=(f[i]<<1)+c[i][j];
/*将读入的n列数据压缩*/
for(int i=0;i<size;i++)pd[i]=((i&(i<<1))==0)&&((i&(i>>1))==0);
/*初始化pd数组, 当前第i状态下草的摆放,左右都没有草 pd[i]=0则表示这个状态不合法或者说这种摆放不合法*/
dp[0][0]=1;//这里一定要初始化,因为dp[1][0]可以继承这个状态
for(int i=1;i<=m;i++)
for(int j=0;j<size;j++)
if(pd[j]&&((j&f[i])==j))
/*
表示当前j状态 草地摆放是合法的,
并且当前行 在这种状态下,的对应位置 草地都是可用的
比如 j=100110 f[i]= 110110 则j&f[i]==j
*/
for(int k=0;k<size;k++)
if((k&j)==0)
dp[i][j]=(dp[i][j]+dp[i-1][k])%maxn;
/*
第一个循环表示当前第几行,
第二个循环表示当前行 可以不可以以j的状态摆放
第三个循环表示 当前行的状态确定下,
上一行 是什么状态,有什么摆放状态可以转移过来
并且要满足,每块草地上下左右没有公共边
*/
int ans;
for(int i=0;i<size;i++)
ans=(ans+dp[m][i])%maxn;
printf("%d",ans);
return 0;
}