状态压缩动态规划,即状压dp,是利用二进制表示状态的一种dp。
根据题意,标记为1的土地只有有人(1)和无人(0)两种状态,所以状压显而易见。

记dp[i][j]表示第i行状态为j的方案数,初始化dp[0][0]=1;同时采用二进制数ar[i]记录第i行的土地状态。
首先,对于每一行i,状态j必须是合法的,得到((j|ar[i])==ar[i])&&(j&(j>>1)==0),因为方案不能与土地冲突,同时同一行相邻的两个不能同时为1。
其次,考虑第i-1行状态k转移到第i行状态j,得到(j&k)==0,因为同一列相邻两个不能同时为1,求得转移方程:dp[i][j]=图片说明 dp[i-1][k]。
最后求和图片说明 dp[n][i]即可。

代码:

#include <iostream>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <functional>
#include <string>
#include <cstring>
#include <sstream>
#include <deque>
using namespace std;

typedef long long ll;
typedef pair<int,int> P;
typedef pair<P,int> Q;

const int inf1=1e9+9;
const ll inf2=8e18+9;
const ll mol=1e8;
const int maxn=15;
const int maxx=1<<maxn;

int n,m,ar[maxn];
int dp[maxn][maxx]={1};

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(dp,0,sizeof dp); dp[0][0]=1;
        memset(ar,0,sizeof ar);
        for(int i=1;i<=n;i++)
            for(int j=0;j<m;j++)
            {
                int num;
                scanf("%d",&num);
                ar[i]+=(num<<j);
            }
        for(int i=1;i<=n;i++)
            for(int j=0;j<(1<<m);j++)
                if(((j|ar[i])==ar[i])&&((j&(j>>1))==0))
                    for(int k=0;k<(1<<m);k++)
                        if((j&k)==0) dp[i][j]=(dp[i][j]+dp[i-1][k])%mol;
        int sum=0;
        for(int j=0;j<(1<<m);j++) sum=(sum+dp[n][j])%mol;
        printf("%d\n",sum);
    }
}