ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

POJ Corn Fields 状态压缩DP基础题

2019-04-16 13:44:56  阅读:366  来源: 互联网

标签:状态 格子 int Fields Corn ++ POJ 玉米 dp


题目链接:http://poj.org/problem?id=3254
题目大意(名称什么的可能不一样,不过表达的意思还是一样的):
种玉米
王小二从小学一年级到现在每次考试都是班级倒数第一名,他的爸爸王大强觉得读书对于王小二来说应该是没有出路了,于是决定让王小二继承自己的衣钵,从事一份非常有前途的工作——种玉米。王大强是一位富有的农场主,他拥有一块 M*N 平方米的矩形田地专门用来种玉米(1<=M,N<=12)。这个玉米地被分成了 M*N 个,每个格子是一个大小为1平方米的格子。这块玉米地中有一些格子因为还没有开垦,所以上面长满了岩石,所以这些格子是不适合种玉米的。相邻的格子也是不能同时种玉米的,因为如果这么做了的话,两个格子区域的玉米因为相互抢夺土壤里面的资源结果会都长不好。
虽然王小二的成绩不好,但是他是一个喜欢思考的人,他想要知道一共有多少种可行的方式来种玉米。

输入

第一行包括两个正数M和N。
接下来M行每行包含N个整数,数字1表示这个格子是适合种玉米的,数字0表示这个格子不适合种玉米。

输出

输出一个整数,表示种玉米的方案数。(除 100,000,000 取模)

样例输入

2 3
1 1 1
0 1 0

样例输出

9

题目分析:这道题目可以用状态压缩DP来处理。
dp[i][j] 表示第i行的状态取为j的时候的方案总数,那么这个j的状态是什么意思呢?
j虽然是一个整数,但是它其实表示的是一行的所有二进制状态。
比如,如果我们某一行的三个格子分别是:种、不种、种,我们用 1 表示“种”,用 0 表示“不种”, 那么这一行其实可以表示成 1,0,1 对应的二进制数就是 101 ,这个数对应的十进制的数就是 1*4+0*2+1*1 = 5
我们还要过滤一下每一行的状态,第i行的状态j成立的条件是:

  • j对应的状态上没有在有岩石的格子上种玉米;
  • j对应的状态不会有连续的两列上种玉米。

这两点我在代码上面有比较明确的体现。
然后我们就可以得到状态转移方程:

dp[i][j] = 1, 其中i==0(第0行),j是第i行的合理状态(满足上面提到的两个条件)
dp[i][j] = sum(dp[i-1][k]),其中i>0,j是第i行的合理状态,k是第i-1行的所有合理状态的集合,并且j和k状态满足关系式:j&k==0,对应的字面意思就是不存在连续的两行同一列都种着玉米

最后的结果就是 sum(dp[M-1][j]),其中j对应第M-1的所有合理状态。

代码:

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 13;
const int MOD = 100000000;

int M, N, dp[maxn][1<<maxn], g[maxn][maxn];
vector<int> states[maxn];

void test() {
    for (int i = 0; i < M; i ++) {
        cout << (i+1) << "(" << states[i].size() << "): ";
        int sz = states[i].size();
        for (int j = 0; j < sz; j ++) {
            if (j) cout << ",";
            cout << states[i][j];
        }
        cout << endl;
    }
    cout << "check:" << endl;
    for (int i = 0; i < states[M-1].size(); i ++) {
        if (dp[M-1][i]) {
            cout << "\t" << i << " : " << dp[M-1][i] << endl;
        }
    }
}

int main() {
    while (cin >> M >> N) {
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < M; i ++) {
            for (int j = 0; j < N; j ++) {
                cin >> g[i][j];
            }
        }
        for (int i = 0; i < M; i ++) {
            states[i].clear();
            for (int j = 0; j < (1<<N); j ++) {
                bool flag = true;
                // 判断是否在岩石上种了玉米
                for (int k = 0; k < N; k ++) {
                    if (g[i][k] == 0 && j&(1<<k)) {
                        flag = false;
                        break;
                    }
                }
                // 判断是否相邻的格子都种了玉米
                if (flag) {
                    for (int k = 0; k < N-1; k ++) {
                        if (j&(1<<k) && j&(1<<(k+1))) {
                            flag = false;
                            break;
                        }
                    }
                }
                if (flag) {
                    states[i].push_back(j);
                }
            }
        }
        int sum = 0;
        for (int i = 0; i < M; i ++) {
            int sz = states[i].size();
            for (int j = 0; j < sz; j ++) {
                int p = states[i][j];
                if (i == 0) dp[i][p] = 1;
                else {
                    int sz2 = states[i-1].size();
                    for (int k = 0; k < sz2; k ++) {
                        int q = states[i-1][k];
                        if (!(p&q)) {
                            dp[i][p] += dp[i-1][q];
                            dp[i][p] %= MOD;
                        }
                    }
                }
                if (i == M-1) {
                    sum += dp[i][p];
                    sum %= MOD;
                }
            }
        }
        cout << sum << endl;
        // test();
    }
    return 0;
}

标签:状态,格子,int,Fields,Corn,++,POJ,玉米,dp
来源: https://www.cnblogs.com/zifeiy/p/10716427.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有