poj-2411 Mondriaan's Dream (狀態壓縮dp)

題意:給你一個h*w的矩陣,讓你使用一個1*2的板子把矩陣覆蓋完全,不能重疊且不能有空缺,問有多少種覆蓋方法。

思路:首先我們可以知道木板的擺放有3種方法,橫着放,豎着放,不放。

    我們設定橫着放佔兩格狀態爲11,不放佔一格爲0,豎着的情況特殊處理,因爲它佔了兩行,我們設定上一行爲0下一行爲1使得對下一行的位置產生影響並且在上一行有所標記。我們可以用dfs來枚舉所有的兩行間情況。

       當橫放的時候要求上一行都沒有空缺所以,now<<2|3,pre<<2|3。

當豎放的時候上一行空下一行不空,now<<1|1,pre<<1。

當不放的時候上一行不空下一行空,now<<1,pre<<1|1。(爲什麼不是兩行都空,兩行都空自然能放一個豎板……)

    枚舉完之後,由於上一行全部爲1時下一行可以任意放置所有情況。所以初始化dp[0][(1<<w)-1]=1。之後對於每一個pre都有對應的now讓dp[i][now]+=dp[i-1][pre]統計個數

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#define INF 0x3f3f3f3f
#define mod 100000000
using namespace std;

struct node
{
    int now,pre;
}a[200000];
long long dp[20][5000];
int h,w,cnt;
void dfs(int l,int now,int pre)
{
    if(l>w) return ;
    if(l==w)
    {
        a[cnt].now=now;
        a[cnt++].pre=pre;
        return ;
    }
    dfs(l+1,now<<1,pre<<1|1);
    dfs(l+1,now<<1|1,pre<<1);
    dfs(l+2,now<<2|3,pre<<2|3);
}
int main()
{
    while(scanf("%d%d",&h,&w),h||w)
    {
        cnt=0;
        memset(dp,0,sizeof(dp));
        dfs(0,0,0);
        dp[0][(1<<w)-1]=1;
        for(int i=1;i<=h;i++)
        {
            for(int j=0;j<cnt;j++)
            {
                dp[i][a[j].now]+=dp[i-1][a[j].pre];
            }
        }
        printf("%lld\n",dp[h][(1<<w)-1]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章