poj2411 Mondriaan's Dream【插头dp】

题目大意:

12 的矩形铺满 nm 的大矩形,问有多少种方案。 1n,m11

解题思路:

这道题所说可以用状压dp来做,但用插头dp可以做到更优秀的复杂度。

首先这道题只用考虑每段轮廓线上有无插头即可,按格转移,所以时间复杂度为 O(n22n+1)

每个有以下四种情况:
这里写图片描述
分类讨论即可。

插头dp建议用滚动数组,这样换行的时候好转移。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<set>
#include<complex>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=12;
int n,m;
ll f[N][1<<N];

int main()
{
    //freopen("lx.in","r",stdin);
    while(1)
    {
        n=getint(),m=getint();
        if(n+m==0)break;
        if(n<m)swap(n,m);
        memset(f,0,sizeof(f));//清零 
        int now=0,mx=1<<(m+1);
        f[now][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                now^=1;
                for(int k=0;k<mx;k++)f[now][k]=0;//由于是滚动数组,这里每次也都要清零 
                int p=1<<(m+1-j),q=1<<(m-j);//该格两个插头位置。 
                for(int k=0;k<mx;k++)
                {
                    int k0=k;
                    if(j==1)                //换行 
                    {
                        if(k0&1)continue;   //如果最右边还有向外的插头则为不合法 
                        k0>>=1;             //换行时要把竖插头从最后移到最前面 
                    }
                    int p0=k0&p,q0=k0&q;    // 该格两个插头当前状态 
                    int kk=k0-p0-q0;
                    if((p0&&!q0)||(!p0&&q0))f[now][kk]+=f[now^1][k];//情况1、2 
                    if(!p0&&!q0)                                    //情况3、4 
                    {
                        f[now][kk|p]+=f[now^1][k];
                        f[now][kk|q]+=f[now^1][k];
                    }
                }
            }
        cout<<f[now][0]<<'\n';              //最后一格只有状态全为0才是合法的。 
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值