poj 2411 Mondriaans Dream (状压DP)

来源:互联网 发布:淘宝点火炬微信群 编辑:程序博客网 时间:2024/04/30 05:59

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

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;#define maxn 11typedef __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预处理出两行之间的所有合法的状态转移:

这里写图片描述

#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 14000LL 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))
暂时还不会

0 0
原创粉丝点击