哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级)B 小乐乐搭积木 (状态压缩)

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小乐乐想要给自己搭建一个积木城堡。
积木城堡我们假设为n*m的平面矩形。
小乐乐现在手里有1*2,2*1两种地砖。
小乐乐想知道自己有多少种组合方案。

输入描述:

第一行输入整数n,m。(1<=n,m<=10)

输出描述:

输出组合方案数。
示例1

输入

复制
2 3

输出

复制
3

说明

示例2

输入


1 3

输出

复制
0
示例3

输入


2 5

输出


8

题目大意:

给你一块n*m的方块,以及若干1*2的小木板,问你有多少种方式能够使小木板填满方块。

状压DP模板题。和POJ2411雷同。

摘自focus_best的csdn博客:

首先我们定义如下这种填充表示方式:如果一个骨牌是横着放的,那么它所在的两个方格都填充1.如果它是竖着放的,那么它所在的两个格子中,上面的那个填0,下面的这个填1.由此可以得到断言:该矩阵的骨牌摆放方法和该矩阵的二进制表示法是一一对应的。 

现在我们专注于这个问题:如何求相邻两行二进制值的对应关系?可以枚举i-1行的所有二进制值情况,然后判断这个值本身是否合法,如果合法(其实只要这行是中间行所有二进制值都合法的,因为首行我们虚构了第0行为全1序列,最后一行我们只需要全1序列对应的值),再通过它推断出和它兼容的第i行二进制值(和i-1行二进制值兼容的第i行二进制为:第i-1行为0的位,第i行应为1。第i-1行为1的位,第i行为0或1,且如果第i行为1那么表示第i行此时的对应位置是横着放的,应该有偶数个连续的1才合法,只需判断i-1行中为1的位在第i行中如果也为1必须偶数个这样的1相连)。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int mod=1000000007;
const int inf=1000000000;
const int maxn=10;
const int maxm=200;

int n,m;
int dp[maxn+5][2<<(maxn+5)];

int main()
{
    scanf("%d%d",&n,&m);
    memset(dp,0,sizeof(dp));
    dp[0][(2<<(m-1))-1]=1;

    for(int i=1; i<=n; i++)
    {
        for(int k=0; k<=((2<<(m-1))-1); k++)//i行
        {
            if(i==n&&k<((2<<(m-1))-1))
                continue;
            for(int j=0; j<=((2<<(m-1))-1); j++)//i-1行
            {
                bool flag=true;
                for(int p=0,cnt=0; p<=m-1; p++)
                {
                    if((j&(1<<p))==0)
                    {
                        if(cnt%2)
                            flag=false;
                        else
                            cnt=0;
                        if((k&(1<<p))==0)
                            flag=false;
                    }
                    if((j&(1<<p))>0)
                    {
                        if((k&(1<<p))>0)
                            cnt++;
                        else
                        {
                            if(cnt%2)
                                flag=false;
                            else
                                cnt=0;
                        }
                    }
                    if(p==m-1)
                    {
                        if(cnt%2)
                            flag=false;
                    }
                    if(!flag)
                        break;
                }
                if(flag)
                {
                    dp[i][k]+=dp[i-1][j];
                }
            }
        }
    }

    printf("%d\n",dp[n][((2<<(m-1))-1)]);

    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/acboyty/p/10061960.html