poj 2411 Mondriaan's Dream(压缩状态dp)

以前做过一道给定高度,然后给出长度让你求拼凑的方法的题,记得是到递推的题,如果这题不是在dp的训练计划里,我一定会耐心的去推公式的。呃,汗.......

好吧,来说说这题吧。

题意:给出矩形的长和高,然后让你计算用1*2或2*1的小矩形拼凑这个矩形,共有多少种方法?

思路:刚才说了,开始我是想推公式来着,然后看了discuss了的一些讨论,才有了点想法,不过思路不是自己的,就不写了,个人觉得,下面这篇日志里讲的就很详细了~

http://blog.csdn.net/wmn_wmn/article/details/7773167

不过我觉得这题难的不是思路,而是关于二进制位运算的部分,如果不是很了解位运算的话,很难看懂代码的。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#define  N 12
using namespace std ;

typedef long long ll ;

ll dp[N][1<<N] ;
ll st[1<<N] ;
int h , w ;

int ok ( int x )
{
    int i = 0 ;
    while( i < w )
    {
        if ( x & ( 1 << i ))
        i++ ;
        else
        {
            if( x & ( 1 << ( i + 1 )))
            return 0 ;
            if ( i == w - 1 )
            return 0 ;
            i += 2 ;
        }
    }
    return 1 ;
}

int main()
{
    int i , j , k ;

    while( scanf( "%d%d" , &h , &w ) != EOF )
    {
        if ( h == 0 && w == 0 )
        break;

        if ( h % 2 && w % 2 )
        {
            printf ( "0\n" ) ;
            continue ;
        }

        memset( dp , 0 , sizeof ( dp ));
        if ( h < w )
        {
            int tem = h ;
            h = w ;
            w = tem ;
        }
        //初始化。
        int num = 0 ;
        for ( i = 0 ; i < ( 1<<w ) ; i++ )
        {
            if ( ok ( i ))
            {
                dp[0][i] = 1 ;
                st[num++] = i ;
            }
        }
        
        //修改每行的状态
        for ( i = 1 ; i < h ; i++ )
        {
            for ( j = 0 ; j < num ; j++ )
            {
                for ( k = 0 ; k < ( 1<<w ) ; k++ )
                {
                    if ( ( st[j] & k ) != k )
                    continue ;
                    dp[i][st[j]^k] += dp[i-1][k] ;
                }
            }
        }
        cout<<dp[h-1][0]<<endl;
    }
    return 0 ;
}
posted @ 2012-08-13 15:09  Misty_1  阅读(171)  评论(0编辑  收藏  举报