poj 3254 Corn Fields(状压dp入门及详解)

题意:农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
Input
第一行:两个整数M和N,用空格隔开。
第2到第M+1行:每行包含N个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块土地不适合种草。
Output
一个整数,即牧场分配总方案数除以100,000,000的余数。
Sample Input
2 3
1 1 1
0 1 0
Sample Output
9

思路:可以参考这位大佬的博客,下面的代码是根据我自己的理解写的

详见代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int mod = 100000000;
int n, m;
int cur[20];//cur[i]表示第i行的状态
int  dp[20][5000];//dp[i][j]表示前i行,第i行状态为j时的的方案数
int state[500];//表示可行状态集合
int top;
void init() {//预处理所有可行状态
    int sum = 1 << m;
    for(int i = 0; i < sum; i++) {
        if(i & (i << 1)) continue;//让当前数字和左移一位进行比较,如果有连续的1,就continue
        else state[++top] = i;
    }
}
int fit(int i, int num) { //判断第num行能不能变成第i种可行状态,判断一行的
    if(state[i]&cur[num]) return 0;
    return 1;
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            int x;
            scanf("%d", &x);
            if(x == 0) cur[i] += 1 << (m - j);//预处理cur
            /*
            这里将原来数据为0的存储为1,原来是1的存储为0,
            是为了方便与预处理后的状态进行对比
            举个例子:原来数据是1 1 1 ——>存储后:0 0 0
            然后这里m==3,所以预处理可行状态有5种,
            分别是 0 0 0(1表示放了草,0表示没放草)
                   1 0 0
                   0 1 0
                   0 0 1
                   1 0 1
                   然后这里将存储后的 0 0 0 与5种可行状态进行位与操作
                   发现结果都是0,所以都是可行的,
                   换句话说就是看原草地能不能通过种植草变成当前对比的可行状态
            */
        }
    }
    init();
    for(int i = 1; i <= top; i++) {
        if(fit(i, 1)) dp[1][i] = 1;//dp的初始化
    }
    for(int i = 2; i <= n; i++) { //遍历每一行
        for(int j = 1; j <= top; j++) { //遍历可行状态
            if(fit(j, i) == 0) continue;//如果当前行不能够变成第j种可行状态,那就判断下一种
            for(int k = 1; k <= top; k++) {/*如果满足了当前行可以变成可行状态,
                    那么根据题目要求还必须要求上一层(i-1层)也必须是某一种可行状态,
                    同时第i层和第i-1层也不能有上下同一位置都为1的情况
                */
               if(fit(k, i - 1) == 0) continue;//i-1层满足可行状态
                if(state[j]&state[k])continue;//第i层和第i-1层的可行状态不能有冲突
                dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;//dp的更新
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= top; i++) ans = (ans + dp[n][i]) % mod;
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/80522614