记录一个菜逼的成长。。
一道状态压缩DP入门的题。学习下状压DP。
题目大意:
给你一个n*m的图。为0不能放羊,为1可以放羊,一个格子只能放一只羊,并且不能有羊相邻的情况有多少种。
状态压缩就是将状态用一个十进制数来表示,十进制数用二进制表示就可以表示状态,所以会用到位运算。
dp[i][j]:=第i行状态为j的方案数;
对于可以放羊的位置,如果放羊则为1,不放则为0;
样例第一行有8种情况,分别为 000,001,010,100,011(不符),101,110(不符),111(不符)
第二行有两种情况,分别为000,010
而010这种情况又跟第一行的010冲突,所以对于000情况又5种,对于010有4种,加起来是9种。
所以判断的时候不仅要判断同行相邻,还要判断与上一行相邻的情况。
对于样例,m = 3,所以将状态压缩为8.即1<<3。在二进制下有三位,可以用来表示状态。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <list>
#include <stack>
#include <deque>
#include <cctype>
#include <bitset>
#include <cmath>
using namespace std;
#define ALL(v) (v).begin(),(v).end()
#define cl(a) memset(a,0,sizeof(a))
#define fin freopen("D://in.txt","r",stdin)
#define fout freopen("D://out.txt","w",stdout)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
typedef vector<PII> VPII;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int mod = 100000000;
const int maxn = (1<<12) + 10;
int dp[15][maxn];
int g[15][15],two[15];
vector<int>a[15];
int n,m;
//预处理2的幂次
void init()
{
two[0] = 1;
for( int i = 1; i < 15; i++ )
two[i] = two[i-1] << 1;
}
int fun(int x)
{
int ret = 0;
for( int i = 1; i <= m; i++ ){
ret += (!g[x][i]) * two[m-i];//注意这里是g[x][i]为0 ,与下面的判断放羊是否合法对应
}
return ret;
}
int main()
{
init();
while(~scanf("%d%d",&n,&m)){
cl(a);cl(dp);
for( int i = 1; i <= n; i++ ){
for( int j = 1; j <= m; j++ ){
scanf("%d",g[i]+j);
}
}
int k = 1 << m;
//处理边界的情况
for( int i = 0; i < k; i++ )
dp[0][i] = 1;
a[0].push_back(0);
for( int i = 1; i <= n; i++ ){
int tmp = fun(i);//这行的状态
for( int j = 0; j < k; j++ ){
if(j & (j >> 1))continue;//判断同行是否相邻
if(j & tmp)continue;//判断放羊是否合法
a[i].push_back(j);
}
for( int j = 0; j < a[i].size(); j++ ){
int u = a[i][j];
for( int t = 0; t < a[i-1].size(); t++ ){
int v = a[i-1][t];
if(u & v)continue;//判断是否与上一行相邻
dp[i][u] = (dp[i][u] + dp[i-1][v]) % mod;
}
}
}
int ans = 0;
for( int i = 0; i < k; i++ ){
ans = (ans + dp[n][i]) % mod;
}
printf("%d\n",ans);
}
return 0;
}