文章標題 POJ 2411 : Mondriaan's Dream (狀態壓縮DP)

Mondriaan’s Dream

轉自 http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;

const int mod=1e9+7;
const int maxn=1e5+10;

int n,m;
ll dp[15][1<<12];

bool judge(int x){
    for (int i=0;i<m;){
        if (x&(1<<i)){
            if (i==m-1)return false;
            if (x&(1<<(i+1)))i+=2;
            else return false;
        }
        else i++;
    }
    return true;
}

bool OK(int now,int pre){
    for (int i=0;i<m;){
        if ((now&(1<<i))){//第i行第j列爲1
            if (pre&(1<<i)){//第i-1行第j列也爲1,那麼第i行必然是橫放
                //第i行和第i-1行的第j+1都必須是1,否則是非法的
                if (i==m-1)return false;
                if ((now&(1<<(i+1)))==0)return false;
                if ((pre&(1<<(i+1)))==0)return false;
                i+=2;
            }else {
                i++;//第i-1行第j列爲0,說明第i行第j列是豎放
            }
        }else {//第i行第j列爲0,那麼第i-1行的第j列應該是已經填充了的
            if (pre&(1<<i)) i++;//已經填充
            else return false;
        }
    }
    return true;
}

int main()
{
    while (scanf ("%d%d",&n,&m)&&n&&m){
        if ((n&1)&&(m&1)){
            printf ("0\n");
            continue;
        }
        if (n<m)swap(n,m);//交換後n是行m是列,m較小,那麼狀態數也可以相應減少
        memset (dp,0,sizeof (dp));
        for(int i=0;i<(1<<m);i++){//枚舉第一行所有可能的狀態
            if (judge(i)){
                dp[1][i]=1;
            }
        }
        for (int i=2;i<=n;i++){
            for (int j=0;j<(1<<m);j++){
                for (int k=0;k<(1<<m);k++){
                    if (OK(j,k)){
                        dp[i][j]+=dp[i-1][k];
                    }
                }
            }
        }
        printf ("%lld\n",dp[n][(1<<m)-1]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章