zoj 1100 - Mondriaan's Dream
Posted clnchanpin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zoj 1100 - Mondriaan's Dream相关的知识,希望对你有一定的参考价值。
题目:在m*n的地板上铺上同样的1*2的地板砖,问有多少种铺法。
分析:dp,组合,计数。经典dp问题,状态压缩。
状态:设f(i,j)为前i-1行铺满,第i行铺的状态的位表示为j时的铺砖种类数;
转移:由于仅仅能横铺或者竖铺。那么一个砖块铺之前的状态仅仅有两种;
且假设当前竖放会对下一行产生影响,建立相邻两行状态相应关系。
这里利用dfs找到全部f(i。j)的上一行的全部前置状态f(i-1,k)加和就可以。
f(i。j)= sum(f(i-1,k)){ 当中,f(i-1,k)能够产生f(i。j)状态 };
(大黄的三维DP实现简单,效率较差。)
组合学公式 :π(4cos(pi+i/(h+1))^2+4cos(pi+j/(w+1))^2) { 1<=i<=h/2,1<=j<=w/2 }。
说明:纠结N久最后发现%I64d一直WA。%lld就过了。(2011-09-27 19:15)。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct node { int s,l; }seg; seg S[ 10 ]; long long F[ 12 ][ 1<<11 ]; int V[ 1<<11 ][ 99 ]; int Count[ 1<<11 ]; //用dfs找到能够到达的状态 void dfs( int A, int B, int C ) { if ( !A ) { V[ C ][ ++ Count[ C ] ] = B; return; }else { int V = A&-A;//取得最后一个 1的位置 dfs( A&~V, B&~V, C ); if ( A&(V<<1) ) dfs( A&~(3*V), B, C ); } } int main() { int n,m; while ( scanf("%d%d",&n,&m) != EOF && m ) { if ( n%2&&m%2 ) {printf("0\n");continue;} if ( m>n ) {int t = m;m = n;n = t;} int M = (1<<m)-1; for ( int i = 0 ; i <= M ; ++ i ) { Count[ i ] = 0; dfs( i, M, i ); } for ( int i = 0 ; i <= n ; ++ i ) for ( int j = 0 ; j <= M ; ++ j ) F[ i ][ j ] = 0LL; F[ 0 ][ M ] = 1LL; for ( int i = 1 ; i <= n ; ++ i ) for ( int j = M ; j >= 0 ; -- j ) for ( int k = Count[ j ] ; k >= 1 ; -- k ) F[ i ][ j ] += F[ i-1 ][ V[ j ][ k ] ]; printf("%lld\n",F[ n ][ M ]); } return 0; }
以上是关于zoj 1100 - Mondriaan's Dream的主要内容,如果未能解决你的问题,请参考以下文章
poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
ZOJ - 3216:Compositions (DP&矩阵乘法&快速幂)
Inviting Friends(hdu3244 && zoj3187)完全背包+二分
Luogu 2444 [POI2000]病毒 & Zoj 3784