• 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);            //这一列不放,则下一行的这一列可以竖着放一个 
    }
  • 相关阅读:
    HDU5087——Revenge of LIS II(BestCoder Round #16)
    HDU5086——Revenge of Segment Tree(BestCoder Round #16)
    POJ3009——Curling 2.0(DFS)
    POJ2891——Strange Way to Express Integers(模线性方程组)
    算法总结之求解模线性方程组
    Linux运维学习笔记-网络技术知识体系总结
    Linux运维学习笔记-定时任务知识总结
    Linux运维学习笔记-文件权限知识总结
    Linux运维学习笔记-常用快捷键及vi、vim总结
    Linux运维学习笔记-角色知识总结
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7224343.html
Copyright © 2020-2023  润新知