• HDU 1400 (POJ 2411 ZOJ 1100)Mondriaan's Dream(DP + 状态压缩)


    Mondriaan's Dream

    Problem Description
    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
    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
    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
     
    题目大意:用长为2,宽为1的矩形填充满长为h,宽为w的矩形有多少种方案?
     
    分析:

    由于长和宽均小于等于11,故每一行均可用一个2进制数表示其状态。我们用1表示竖放的方格,0表示横放的方格。那么样例中各行的状态分别为:

    00100001100 

    11110011100 

    11110011001 

    00111001001 

    10011000011 

    10000001111 

    00001001100 

    10011100100 

    10011100111 

    00001000011 

    转化为十进制,就是268,1948,1945,457,1219,1039,76,1252,1255,67。

      用dp(i,j)表示第 i 行状态为 j 时,有多少种排法。那么dp(i,j)应该等于前 i-1 行,状态 k 与 j 相符的排法数的和。状态相符,即在 j 二进制数上为1的位,k 一定也为1。在向下递归时,应该把 k 中和 j 二进制状态中同为1的位置为0,即应该求 dp(i-1,k^j),原因是当第 i-1 行与第 i 行相接后,二者同为1的地方消掉了,应该当作0处理。

      所以为了方便,题目描述中那个最大矩阵的第一行就表示为00100001100,第二行就表示为11010010000,这样的话,当上一层j位置为1时,下一层j位置一定为0

    当上一层j位置为0时,下一层j位置可以为1,也可以为0,并且当上下都层为0时,零的个数要为偶数,这样上下层的状态相&为0。

      所以dp(i,j)=sum{dp(i-1,k^j),(k&&j)==0&&judge(k^j)}(judge(k)表示k是有效的行状态,即二进制数状态中连续的0个数为偶数,可先生成存入数组中)。所求答案即为dp(n,0).

      初始化dp(0,i)=0,dp(0,0)=1。

      注意结果要用long long或__int64保存,还有要注意位运算的优先级是很低的。

     

    代码如下:

     1 # include<stdio.h>
     2 __int64 dp[12][1<<12];
     3 int h,w;
     4 
     5 bool judge(int s){    //判断状态s是否成立
     6     int count;
     7     count = 0;    //s中0的个数
     8     for(int i=0;i<w; i++){
     9         if(s & 1){
    10             if(count & 1)    //1的前面0的个数非偶数,不成立
    11                 return false;
    12         }
    13         else
    14             count ++;
    15         s >>= 1;
    16     }
    17     if(count & 1)    //奇数个0,不成立
    18         return false;
    19     else
    20         return true;
    21 }
    22 
    23 int main(){
    24     int i,j,k;
    25     while(scanf("%d%d",&h,&w),h+w){
    26         if((h*w) & 1){        //这种情况下无论如何也不能填满
    27             printf("0
    ");
    28             continue;
    29         }
    30         dp[0][0] = 1;
    31         for(i=1; i<=h; i++)
    32             for(j=0; j<(1<<w); j++){
    33                 dp[i][j] = 0;        //初始化
    34                 for(k=0; k<(1<<w); k++)
    35                     if((j&k)==0 && judge(j^k))
    36                         dp[i][j] += dp[i-1][k];
    37             }
    38         printf("%I64d
    ",dp[h][0]);
    39     }
    40     return 0;
    41 }
  • 相关阅读:
    CCF总结
    句柄的定义
    ubuntu16.04下安装和使用Kdevelop的技巧
    找不到ros相关包的解决方法
    用kdevelop构建ROS程序包
    Linux给软件添加卓面快捷方式
    工程代码结构说明——哈工大编译原理课程(五)
    符号表管理——哈工大编译原理课程(四)
    语义分析和中间代码生成——哈工大编译原理课程(三)
    语法分析器——哈工大编译原理课程(二)
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3289994.html
Copyright © 2020-2023  润新知