【POJ3254】Corn Fields
http://poj.org/problem?id=3254
题意:给你一块n*m(0<n,m<=12)的地图,其中有的方格是肥沃的(用1表示),有的方格是贫瘠的(用0表示)。现在约翰要在肥沃的土地上放奶牛,且要求不能有两个奶牛相邻,请问有多少种方案数。
状压DP入门题。
首先预处理每一行不考虑贫瘠地时所有可行的放置状态,用states数组存着。
然后令f(i,j)为考虑前i行且第i行放置状态为states[j]时的方案数,可得f(i, j)=sigma{f(i-1, k) | states[j]&states[k]==0} (states[j]不包含第j行的贫瘠地),f(i, j)=0(states[j]包含第j行的贫瘠地)。
先计算第一行的方案数,再递推第二行到第n行的方案数,最后答案为sigma{f(n,j)}。具体实现看代码
#include <iostream> #include <vector> using namespace std; template <class T> void update(T &x) { while (x >= 100000000) x -= 100000000; } int r, c, map[13]; // 初始地图 int states[1 << 13], siz = 0; // 不考虑贫瘠地时每一行的所有可行放置方案 int dp[13][1 << 13]; // dp[i][j]表示考虑前i行且第i行放置状态为states[j]时的方案数 int main() { ios::sync_with_stdio(false); cin >> r >> c; for (int i = 0; i < 1 << c; i++) if (!(i & (i << 1))) // 若状态i不存在两个相邻的1 states[++siz] = i; int a; for (int i = 1; i <= r; i++) { for (int j = 0; j < c; j++) { cin >> a; if (!a) map[i] |= (1 << j); } } for (int i = 1; i <= siz; i++) if (!(states[i] & map[1])) // 若状态states[i]不包含第一行的贫瘠地,则出现一种放置方案 dp[1][i] = 1; for (int i = 2; i <= r; i++) { for (int j = 1; j <= siz; j++) // 枚举这一行的放置方案 { if (states[j] & map[i]) // 若状态states[j]包含第i行的贫瘠地 continue; for (int k = 1; k <= siz; k++) // 枚举上一行的放置方案 { if (states[k] & states[j]) // 若状态states[k]与状态states[j]有相同位置的1 continue; update(dp[i][j] += dp[i - 1][k]); } } } int ans = 0; for (int i = 1; i <= siz; i++) update(ans += dp[r][i]); cout << ans; return 0; }