数据大小已经很明显的提示,这题是状压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;
}