zoukankan      html  css  js  c++  java
  • ZOJ 1100 Mondriaan's Dream

    Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways.

    Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!

    Input Specification

    The input file contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.

    Output Specification

    For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.

    Sample Input

    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    2 11
    4 11
    0 0
    

    Sample Output

    1
    0
    1
    2
    3
    5
    144
    51205
    

    看的别人的代码实现的,自己有个地方还是有点没弄懂,就是为什么初始状态设为 dp[0][(1<<w)-1] = 1 ? 没有进行数组滚动优化。

    代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int st[20000][2];        // 第 i 个的状态为 st[i][0] 其下一行的状态是 st[i][1]
    long long dp[12][20000];        // 第 i 行 j 状态的方法数 
    int num;
    
    void dfs(int n, int from, int to);        //从右向左填格子,填了 n 列 
    
    int h, w;
    
    int main(){
    //    freopen("input.txt", "r", stdin); 
        while(cin >> h >> w && h != 0){
            if(h*w % 2){
                cout << 0 << endl;
                continue;
            }
            num = 0;
            dfs(0, 0, 0);
            memset(dp, 0, sizeof(dp)); 
            dp[0][(1<<w)-1] = 1;    //为什么初始状态设为这个?
            for(int i=1; i<=h; i++){    //一行一行地累加 
                for(int j=0; j<num; j++){    //遍历出这一行的每种状态 
                    dp[i][st[j][1]] += dp[i-1][st[j][0]];    //加上到这一行的 st[j][1] 状态的上一行的方法数
                }
            }
            cout << dp[h][(1<<w)-1] << endl;    //输出最后一行摆满时的方法数。 
        }
    } 
    
    void dfs(int n, int from, int to){
        if(n == w){        //正好 w 列了 
            st[num][0] = from;        //将状态存起来 
            st[num][1] = to;
            num++;
            return ;
        }
        if(n > w){        //超过不行 
            return ;
        } 
        dfs(n+2, (from << 2) + 3, (to << 2) + 3);        //这一行横着放,则下一行的这两列也可以横着放一个
        dfs(n+1, (from << 1) + 1, (to << 1));            //竖着放,则下一行的这一列就放不了了
        dfs(n+1, (from << 1), (to << 1) + 1);            //这一列不放,则下一行的这一列可以竖着放一个 
    }
  • 相关阅读:
    用批处理来启动/停止SQL SERVER 2005的服务 【转载】
    c#命名法 【转】
    oracle 隐式游标,显示游标,游标循环,动态SELECT语句和动态游标,异常处理,自定义异常【转载】
    fetch bulk collect into 批量效率的读取游标数据 【转载】
    Oracle 外连接和 (+)号的用法 【转载】
    如何在Oracle中复制表结构和表数据 【转载】
    Oracle 小知识点
    VSS 2005 配置(含录像) 【转载】
    json 详解 【转】
    .NET 2.0 使用最新版的JSON.net 进行反序列化 【转载】
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7224343.html
Copyright © 2011-2022 走看看