【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;
}
原文地址:https://www.cnblogs.com/ssttkkl/p/7624842.html