poj 2411 Mondriaan's Dream

来源:互联网 发布:超图软件成都分公司 编辑:程序博客网 时间:2024/05/04 00:41

    首先注意:最后结果的大小可能超过int型,本人wa了2次,然后也没什么需要注意的了,在想状态转移方程的时候,千万别把当前列和上一列的情况弄混淆了,代码里有注释。

第一种方法:

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#define max(a1,b1) (a1)>(b1)?(a1):(b1)using namespace std;int r,c;bool sta[2100];long long dp[12][2100];bool judge(int x){    int tmp = 0;    while(x>0)    {        if(x&1)        {            tmp++;        }        else if(tmp&1)        {            return false;        }        x >>= 1;    }    if(tmp&1)        return false;        return true;}int main(void){    int kk = 1<<11;    for(int i=0;i<kk;++i)    if(judge(i)) sta[i] = true;    else  sta[i] = false;    while(cin>>r>>c,r||c)    {     int k;     if(r*c%2)//总的格子数为奇数个     {         cout<<"0"<<endl;         continue;     }     k = (1<<r)-1;     memset(dp,0,sizeof(dp));     for(int i=0;i<=k;++i)        if(sta[i])        dp[1][i] = 1;     for(int i=2;i<=c;++i)        for(int j=0;j<=k;++j)//j为上一列的情况           for(int e=0;e<=k;++e)//下一列需要平铺的情况(竖着放的需要按照上一行来确定)        {           if((e^(k)|j)!=k) continue;//竖着放的地方与横着放的地方重叠           int tmp = (k^j)|e;           if(!sta[e]) continue;//           dp[i][tmp] += dp[i-1][j];        }     cout<<dp[c][k]<<endl;    }    return 0;}

第二种方法:


#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#define max(a1,b1) (a1)>(b1)?(a1):(b1)using namespace std;int r,c;bool sta[2100];long long dp[12][2100];bool judge(int x){    int tmp = 0;    while(x>0)    {        if(x&1)        {            tmp++;        }        else if(tmp&1)        {            return false;        }        x >>= 1;    }    if(tmp&1)        return false;        return true;}int main(void){    int kk = 1<<11;    for(int i=0;i<kk;++i)    if(judge(i)) sta[i] = true;    else  sta[i] = false;    while(cin>>r>>c,r||c)    {     int k;     if(r*c%2)//总的格子数为奇数个     {         cout<<"0"<<endl;         continue;     }     k = (1<<r)-1;     memset(dp,0,sizeof(dp));     for(int i=0;i<=k;++i)        if(sta[i])        dp[1][i] = 1;     for(int i=2;i<=c;++i)        for(int j=0;j<=k;++j)//j为上一列的情况           for(int e=0;e<=k;++e)//直接枚举当前列的状态        {           int tmp = j^k;           if((tmp&e)!=tmp)//上一列空的地方在当前列必须为满            continue;           int flag = tmp^e;//除去为填补上一列,剩下的就是当前列需要平铺的           if(sta[flag])           dp[i][e] += dp[i-1][j];        }     cout<<dp[c][k]<<endl;    }    return 0;}


原创粉丝点击