poj 2411 Mondriaans Dream (状压DP)

比较容易理解的解法是直接枚举两行的状态。时间复杂度略高O(n*4^m)。
思路参考了该大牛的:请戳

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 11
typedef __int64 LL;
LL dp[12][1<<11];
int n,m;

bool judge(int s)
{
    int cnt=0;
    while(s)
    {
        if(s&1) ++cnt;
        else {
            if(cnt&1) return 0;
            cnt=0;
        }
        s>>=1;
    }
    if(cnt&1) return 0;
    return 1;
}

bool check(int s1,int s2)
{
    for(int i=0;i<m;)
    {
        if(s1&(1<<i))
        {
            if(s2&(1<<i)){
                if(i+1<m&&(s1&(1<<(i+1)))&&(s2&(1<<(i+1)))) i+=2;
                else return 0;
            }
            else ++i;
        }
        else{
            if(s2&(1<<i)) ++i;
            else return 0;
        }
    }
    return 1;
}

int main()
{
    int i,j,k;
    while(~scanf("%d%d",&n,&m)&&(n+m))
    {
        if(n<m) swap(n,m);
        if(n*m%2) {printf("0\n");continue;}
        memset(dp,0,sizeof(dp));

        for(i=0;i<(1<<m);++i)
            if(judge(i)) dp[1][i]=1;
        for(i=2;i<=n;++i)
            for(j=0;j<(1<<m);++j)
                for(k=0;k<(1<<m);++k)
                    if(check(k,j)) dp[i][j]+=dp[i-1][k];
        printf("%I64d\n",dp[n][(1<<m)-1]);
    }
    return 0;
}

另外一种方法是事先通过DFS预处理出两行之间的所有合法的状态转移:

poj 2411 Mondriaans Dream (状压DP)_第1张图片

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef __int64 LL;
#define maxn 14000
LL dp[12][1<<11];
int n,m,p1[maxn],p2[maxn],cnt;
void dfs(int now,int pre,int dep)
{
    if(dep>m) return;
    if(dep==m){
        p1[cnt]=pre;
        p2[cnt++]=now;
        return;
    }
    dfs(now<<1,pre<<1|1,dep+1);
    dfs(now<<1|1,pre<<1,dep+1);
    dfs(now<<2|3,pre<<2|3,dep+2);
}

int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m)&&(n+m))
    {
        cnt=0;
        if(m>n) swap(n,m);
        dfs(0,0,0);
        memset(dp,0,sizeof(dp));
        dp[0][(1<<m)-1]=1;
        for(i=1;i<=n;++i)
            for(j=0;j<cnt;++j)
                dp[i][p2[j]]+=dp[i-1][p1[j]];
        printf("%I64d\n",dp[n][(1<<m)-1]);
    }
    return 0;
}

当然还可以用轮廓线DP来搞。
枚举每一个格子的轮廓线状态,总时间复杂度为O(n*m*2^min(n,m))
暂时还不会

你可能感兴趣的:(poj 2411 Mondriaans Dream (状压DP))