zoukankan      html  css  js  c++  java
  • poj2411 Mondriaan's Dream (用1*2的矩形铺)

    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 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

    这题可以用状压dp做,用二进制表示每一行的状态,横着的11表示横放,竖着的01表示竖放,然后先初始化第一行的可行状态,因为第一行前没有空行,所以转化后的二进制中如果有奇数个1连一起一定是不可行状态.但对于大于1的行来说,因为可能会有前面一行的矩形竖着放,所以奇数个1连在一起可能是可行的,所以需要另外的判断。可以发现,状态转移过程中,大于1的每一行都要满足两个条件,一个是行内不能有空余的位置(可以用|来实现,很神奇啊),另一个是如果去掉前一行竖着放的矩形遗留在当前行的1,当前状态一定也是可行状态(可以用&来实现,动手画一下),这样就可以把动态转移方程写出来了,我们记dp[i][state]为第i行state状态下的总方案数,那么dp[i][state]=dp[i][state]+dp[i-1][state'],所以最后要求的就是dp[n][(1<<m)-1].

    #include<stdio.h>
    #include<string.h>
    #define ll long long
    int kexing[5000],n,m;
    ll dp[15][5000];
    int panduan(int x)
    {
    	int i,j,tot=0;
    	while(x>0){
    		if(x%2==1){
    			tot++;x=x/2;
    		}
    		else{
    			if(tot%2==1)return 0;
    			tot=0;x=x/2;
    		}
    	}
    	if(tot%2==1)return 0;
    	else return 1;
    }
    
    int check(int x,int y)
    {
    	int i,j,t=(1<<m)-1;
    	if(!( (x|y)==t ) )return 0;
    	return kexing[x&y];
    }
    
    int main()
    {
    	int i,j,k;
    	while(scanf("%d%d",&n,&m)!=EOF)
    	{
    		if(n==0 && m==0)break;
    		memset(dp,0,sizeof(dp));
    		for(i=0;i<(1<<m);i++){
    			if(panduan(i)){
    				kexing[i]=1;dp[1][i]=1;
    			}
    			else kexing[i]=0;
    		}
    		for(i=2;i<=n;i++){
    			for(j=0;j<(1<<m);j++){
    				for(k=0;k<(1<<m);k++){
    					if(check(j,k)){
    						dp[i][j]=dp[i][j]+dp[i-1][k];
    					}
    				}
    			}
    		}
    		printf("%lld
    ",dp[n][(1<<m)-1]);
    	}
    	return 0;
    }



  • 相关阅读:
    设计模式(3)——模版方法模式
    设计模式(2)——工厂模式
    设计模式(1)——单例模式
    哪些SQL语句不能用在事务中
    Max Degree of Parallelism最大并行度配置--缓解CPU压力
    IOC框架--AutoFac
    Log4Net日志详解
    Trace、Debug和TraceSource的使用以及日志设计
    c# System.Diagnostics命名空间--调试并跟踪代码日志
    数据分析必会的六大实用模型
  • 原文地址:https://www.cnblogs.com/herumw/p/9464733.html
Copyright © 2011-2022 走看看