zoukankan      html  css  js  c++  java
  • POJ 2411 状态压缩DP

    题目来源: http://poj.org/problem?id=2411

    题目大意:给一个h*w的方格,现给出1*2和2*1的两种小方块,求出把h*w方格铺满的不同方案数(1<=h,w<=11)

    分析:首先能想到的是如果h*w为奇数,那么肯定不能放满,结果为0

               如何表示状态:从题目看数据很小,那么很容易想到用二进制来表示状态,0表示当前方格没放,1表示放了

               这里用dp[ r ][ cur ]表示前 r-1 行放满,第 r 行状态为 cur 时的方案数,同理,dp[ r-1 ][ lst ]表示前 r-2 行放满,

               第 r-1 行状态为 lst 时的方案数; 状态 lst 是由 cur 状态推出来的( [1] 为什么?),

               所以dp[ r ][ cur ] = dp[ r ][ cur ] +dp[ r-1 ][ lst ]; 那么dp[ h ][ (1<<w)-1 ] 即为最后所求结果

               [1] 先表示一下状态,我们在考虑第 r 行,只考虑前 r 行,一共有 3 种状态(cur表示第 r 行,lst表示第 r-1 行):

                         1、竖直放    cur<<1 | 1 ,   lst<<1 

                         2、横着放    cur<<2 | 3,    lst<<2 | 3

                         3、不放        cur<<1,         lst<<1 | 1

               先解释一下:假设 cur = lst = 0,   假如竖直放,那么 cur = 1, lst = 0, 意思是第 r 行第1列放,第 r-1 行第1列

               不放(因为第 r 行要坚直放,所以第 r-1 行第 1 列不能放),直到放完最后一列,出现了两个状态 cur 和 lst,

               其中 lst 不就是由 cur 状态推出来的么?并且保证第 r-1 行是满的!

               其中第一行只有两种状态,因为第一行上边没有,所以不能竖直放……

               举个例子:h = 3, w = 2;      dp[ r ][ cur ] += dp[ r-1 ][ lst ];

              

       仔细看一看应该就可以看的懂了!下面是代码:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #include<string>
    #include<cstdio>
    #include<vector>
    using namespace std;
    
    int h, w;
    long long dp[12][2100];
    
    void dfs(int r, int c, int cur, int lst) {
        if(r == 1) { // if r == 1 only have two state
            if(c == w) { 
                dp[r][cur]++; 
                return ; 
            }
            if(c + 1 <= w) dfs(r, c+1, cur<<1, lst);
            if(c + 2 <= w) dfs(r, c+2, cur<<2|3, lst);
        }
        else {
            if(c == w) { // one state occurs
                dp[r][cur] += dp[r-1][lst];
                return;
            }
            if(c + 1 <= w) { 
                dfs(r, c+1, cur<<1|1, lst<<1);
                dfs(r, c+1, cur<<1, lst<<1|1);
            }
            if(c + 2 <= w) {
                dfs(r, c+2, cur<<2|3, lst<<2|3);
            }
        }
    }
    
    int main() {
        while(~scanf("%d%d", &h, &w)) {
            if(h + w == 0) break;
            if((h*w) & 1) {
                puts("0"); continue;
            }
            if(h < w) swap(h, w);
            memset(dp, 0, sizeof(dp));
            for(int r = 1; r <= h; ++r)
                dfs(r, 0, 0, 0);
                
            printf("%lld
    ", dp[h][(1<<w)-1]);
        }
        return 0;
    }
    



    如有错误欢迎指正。

  • 相关阅读:
    提前期分类
    物料属性,MRP/MPS属性
    ASP.NET刷新页面的一些方法
    Nothing 和 Is
    三层架构与MVC
    ADO.NET
    软件工程之数据流程图(DFD Data Flow Diagram)
    VB.NET小结
    推荐开发人员看的具有影响力的书籍
    C++考试
  • 原文地址:https://www.cnblogs.com/yaling/p/3657202.html
Copyright © 2011-2022 走看看