poj 2411 Mondriaan's Dream

    首先注意:最后结果的大小可能超过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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值