poj 2411 Mondriaan's Dream(状态压缩DP)

来源:互联网 发布:软件测试原则 编辑:程序博客网 时间:2024/05/16 18:10

看到discuss里面有人在晒各种20+行的代码,太犀利了!

开始一直想不到怎么编码,后来还是看了别人的思路,横着放记录为11,竖着放记录为竖着的01,即在该行为0,在下一行为1。这样的,第一行的初始状态中就不能出现连续的奇数个1,而且两行之间没有竖着的00。在两行合并的时候,同样不允许出现(j&k)中出现连续奇数个1(凡是在上一行是竖着放的,j&k后都为0),而两种状态加合的前提是(i|j==t-1),保证方格填满。

非常精巧的编码方式。

#include<stdio.h>#include<string.h>#define N 12typedef long long LL;int st[1<<N];LL dp[N][1<<N];int judge(int x){    int cnt=0;    while(x)    {        if(x&1)            cnt++;        else        {            if(cnt&1)                return 0;            cnt=0;        }        x>>=1;    }    if(cnt&1) return 0;    return 1;}void Init(){    int i,t;    t=1<<11;    for(i=0;i<t;i++)    {        if(judge(i))            st[i]=1;    }    return ;}int main(){    int n,m;    Init();    while(scanf("%d%d",&n,&m),m+n)    {        if((m*n)%2!=0)        {            printf("0\n");            continue;        }        int i,j,k,t;        memset(dp,0,sizeof(dp));        t=1<<m;j=0;        for(i=0;i<t;i++)        {            if(st[i])                dp[1][i]=1;        }        for(i=2;i<=n;i++)        {            for(j=0;j<t;j++)                for(k=0;k<t;k++)                {                    if((j|k)!=t-1||st[(j&k)]!=1)                        continue;                    dp[i][j]+=dp[i-1][k];                }        }        printf("%I64d\n",dp[n][t-1]);    }    return 0;}


原创粉丝点击