zoukankan      html  css  js  c++  java
  • poj3254 Corn Fields(状态dp)

    状态dp一般就是用二进制位来表示当前状态,本质还是动态规划,所以要找到转移方程,一般dp需要满足的就是最优子结构、无后效性,状态dp可能加入了一些位运算,加快程序的执行。

    题目大意:给出一个M*N的矩阵,元素为0表示这个地方不能种玉米,为1表示这个地方能种玉米,现在规定所种的玉米不能相邻,即每行或者没列不能有相邻的玉米,问一共有多少种种植方法。

    举个例子:

    2 3
    1 1 1
    0 1 0
    表示2*3的玉米地,现在一共有多少种种植方法呢? 答案:种0个玉米(算一个合法方案)+种1个玉米(4)+种2个玉米(3)+种3个玉米(1)=9

    我们分析每一行种植玉米的状态其实之和前一行的种植状态有关系,和它前面的其余行没关系,这个满足无后效性,题目让我们求的是方案总数,其实就是求最后一行的所有状态的方案数加和。
    令dp[i][state]表示第i行状态为state的方案数,那么dp[i][state] += dp[i-1][pre_state],这里pre_state和state必须满足条件,1:不相邻 2:pre_state和state是可以存在的,因为
    有的地不能种植玉米,相应位不能为1,该转移方程可以理解为前一行的每一个pre_state都为第i行达到状态state贡献了dp[i-1][pre_state]个方案数。这个和用1*2覆盖地板的那个方案一样。
    有几个位运算的技巧:
    1.不考虑地是否可以种植,先就状态上考虑合法的种植方法,位运算如下
    View Code
    void getvalidstate()
    {
        for(int i = 0; i < (1<<col); ++i)
        {
            if(0 == (i&(i<<1)))
                vst[vnum++] = i;
        }
    }

    2.考虑当前行土地的情况,看一个状态是否合法,位运算如下

    View Code
    bool valid(int state, int r)
    {
        int rstate = 0;
        for(int i = 1; i <= col; ++i)
        {
            if(matrix[r][i])
                rstate += (1<<(col - i)); //得到当前行状态
        }
        if(!(state&(~rstate))) 
            return true;
        return false;
    }

    3.两个状态是否合法,即不能相邻,位运算如下:

    !(curstate&prestate)

    代码如下:

    View Code
    #include <iostream>
    #include <cstring>
    #include <stdlib.h>
    #include <stdio.h>
    using namespace std;
    const int MOD = 100000000;
    const int MAXN = 13;
    const int MAXSTATE = 8193;
    int dp[MAXN][MAXSTATE];
    int matrix[MAXN][MAXN];
    int vst[MAXSTATE];
    int vnum = 0, row = 0, col = 0;
    //get valid state num
    void getvalidstate()
    {
        for(int i = 0; i < (1<<col); ++i)
        {
            if(0 == (i&(i<<1)))
                vst[vnum++] = i;
        }
    }
    bool valid(int state, int r)
    {
        int rstate = 0;
        for(int i = 1; i <= col; ++i)
        {
            if(matrix[r][i])
                rstate += (1<<(col - i));
        }
    //    printf("r state : %d %d\n", r, rstate);
        if(!(state&(~rstate)))
            return true;
        return false;
    }
    int main()
    {
        int m, n, i, j;
        while(EOF != scanf("%d%d", &m, &n)){
        for(i = 1; i <= m; ++i)
            for(j = 1; j <= n; ++j)
                scanf("%d", &matrix[i][j]);
        row = m;
        col = n;
        vnum = 0;
        getvalidstate();
        memset(dp, 0, sizeof(int)*MAXN*MAXSTATE);
        dp[0][0] = 1;
        for(i = 1; i <= row; ++i)
        {
            for(int st = 0; st < vnum; ++st)
            {
                if(valid(vst[st], i))
                {
                    for(int pst = 0; pst < vnum; ++pst)
                    {
                        if(valid(vst[pst], i - 1) && !(vst[st]&vst[pst]))
                            dp[i][vst[st]] += dp[i - 1][vst[pst]];
                    }
                }
            }
        }
        int ret = 0;
        for(i = 0; i < vnum; ++i)
        {
            ret = (ret + dp[row][vst[i]])%MOD;
        }
        printf("%d\n", ret);
      }
    }
  • 相关阅读:
    改进RazorPad
    ViewBag、ViewData和TempData的使用和区别
    MVC3路由设置访问后缀 html jsp
    RazorPad中的ModelProvider
    使用NUnit进行项目的单元测试
    有关WCF的契约问题
    常用的Windows批处理
    SmartBusinessDevFramework架构设计-2:结构图示
    SQL中查询语句的使用
    林子祥
  • 原文地址:https://www.cnblogs.com/buptLizer/p/2650717.html
Copyright © 2011-2022 走看看