POJ 3254 - 状压dp
题目大意:
给一个地图,有障碍0,空地1,规定任意两头奶牛不能相邻且不能在障碍上面,问有多少种方法(一个都不放也算)。
题目分析
状态压缩: 首先将地图的每一行处理成用二进制表示Map[]。然后初始化每一行可能的情况(无用状态太多)存入State[].
dp[i][S]表示考虑到第i行且第i行状态为S的方案数。
\[dp[i][S] += dp[i - 1][valid S']
\]
中间进行些许剪枝(见代码)。
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N = 15, S = 40000, Mod = 100000000;
int n, m;
int Map[N];
typedef long long ll;
int state[S], scnt, ans;
int dp[N][S];
inline int DP(int u, int st){
if(u == 1) return dp[1][st] = 1;
if(dp[u][st] != -1) return dp[u][st];
int t = 0;
for(int i = 1; i <= scnt; i++){
if((state[i] & Map[u - 1]) || (state[i] & st)) continue;
t += DP(u - 1, state[i]);
}
return dp[u][st] = t;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL), cout.tie(NULL);
cin >> n >> m;
memset(dp, -1, sizeof dp);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
int x; cin >> x;
if(!x) Map[i] |= (1 << (j - 1));
}
for(int s = 0; s < (1 << m); s++){
if(s & (s << 1)) continue;
state[++scnt] = s;
}
for(int i = 1; i <= scnt; i++){
// int s = state[i]; cout<<state[i]<<" ";
// while(s) cout<<s%2, s /= 2;cout<<endl;
if(state[i] & Map[n]) continue;
ans = (ans + DP(n, state[i])) % Mod;
}
cout << ans << endl;
return 0;
}