1. 程式人生 > >Mondriaan's Dream POJ

Mondriaan's Dream POJ

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

大致題意:讓你用1*2規格的小矩形去覆蓋n*m的矩陣,不能重疊,問有多少種方案恰好鋪滿

思路:對於當前行的某一列,如果我們豎著鋪,那麼會對下一行造成影響,如果橫著鋪,則不會。我們用二進位制表示當前一行所鋪格子的狀態,然後預處理出從當前行的狀態state1所能夠轉移到的下一行的狀態state2。最後遍歷每一行,進行簡單的狀壓dp即可。

程式碼如下

#include <cstdio>  
#include <cstring>  
#include <algorithm> 
#include <iostream> 
#include <vector>
using namespace std;  
#define ll long long   
int n,m;

ll dp[15][(1<<15)];
vector<int> Nex[(1<<15)];

void dfs(int j,int state,int nex)//準備放第j列,判斷從當前行狀態state所能能變換到的下一行的狀態nex 
{
    if(j==m)//填完了m列 
    {
        Nex[state].push_back(nex);
        return;
    }
    if((1<<j)&state) dfs(j+1,state,nex);//不能填 
    else
    {
        //豎著
        dfs(j+1,state,nex|(1<<j));
        //判斷能不能橫著 
        if(j+1<m&&(1<<(j+1)&state)==0)
        dfs(j+2,state,nex); 
    }
}
int main ()  
{    
    while(scanf("%d%d",&n,&m)&&(n+m))
    {   

        memset(dp,0,sizeof(dp));
        for(int i=0;i<(1<<m);i++)
        Nex[i].clear();

        for(int state=0;state<(1<<m);state++)//列舉當前行的所有狀態
        dfs(0,state,0);

        dp[0][0]=1;
        for(int i=0;i<n;i++)//列舉第i行 
        {
            for(int state=0;state<(1<<m);state++) //列舉第i行放置的情況 
            {
                if(dp[i][state])//如果第i行的狀態state可達
                {
                    int len=Nex[state].size();
                    for(int j=0;j<len;j++)//列舉當前狀態可以轉移到的下一個狀態
                    {
                            int nex=Nex[state][j];
                            dp[i+1][nex]+=dp[i][state];
                    }   
                }   
            }
        }

        printf("%lld\n",dp[n][0]);
    }   
    return 0;  
}