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