状态压缩动态规划,即状压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); } }