poj3411

3 篇文章 0 订阅
Mondriaan's Dream
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 11165 Accepted: 6493

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

Source

Ulm Local 2000
嘛~嘛~就是这样,题意很简单,不知道有木有同学想到用1X2的矩形去塞3Xn有多少种情况那道题了呢?那一道题可以找规律,也可以数学分析,但是通用的方法是用状态压缩动态规划,简称状压DP,就是用某种方式表示出当前的状态,然后转移。
本题状态表示方式&需要知道:
1:在摆放当前行时,上一行一定没有没有被覆盖的点。
2:当前行没有空格地摆完后,在下一行上如果有覆盖,就在相应位置填上1,其它填零,那么当前行的状态就由组成的这个二进制数表示,进而进行转移。
3:每一行转移到下一行的模式是完全相同的,因此可以考虑使用矩阵乘法,但是这一题不用矩阵乘法也能过,因为数据范围太低了。
下面上代码,应该是我参照某位大神的代码写的:
#include<cstdio>
#include<cstring>
long a,b,c,d,h,w;
long long arr[12][2049];//根据数据范围,每一行有最多2^11==2048种状态
bool judge(long k)
{
    long i,j=0;
    for (i=0;i<w;i++)
    {
        if (k&1&&j&1)     //这句话比较难理解,k表示的是二进制当前列上的数,j表示的是当前位置上0的连续个数,如果为奇数当然没法填啦,因为处理过的部分只能横着放,必须是偶数。
              return(0);
        else if (!(k&1))
          j++;
        k>>=1;
    }
    if (j&1) return(0);
    return(1);
}
long long dp()
{
    long i,j,k,l;
    j=1<<w;
    memset(arr,0,sizeof(arr));
    for (i=0;i<j;i++)
      arr[1][i]=judge(i);    //判断第一行当前状态能否满足无空格
    for (i=2;i<=h;i++)
      for (k=0;k<j;k++)
        for (l=0;l<j;l++)
        if (!(k&l)&&(arr[1][l|k]))//比较难理解,判断上一种状态能否转移到这种状态的条件有1:对应位置上不能同时为1(否则没法放);2:除了竖着放的,连续横着的空格数必须为偶数。
          arr[i][k]+=arr[i-1][l];
    return(arr[h][0]);
}
int main()
{
    while (scanf("%ld %ld",&h,&w),h+w)
        if ((h&1)&&(w&1)) printf("0\n");//如果为奇数个方格直接输出无解
        else printf("%lld\n",dp());
    return(0);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值