广场铺砖问题(状压DP入门)

前置知识:

    :按位取与(&) : 0 & 0 = 0 , 0 & 1 = 0 , 1 & 0 = 0 , 1 & 1 =1.

  :按位取或( | ): 0 | 0 =0 , 0 | 1 =1 , 1 | 0 = 1 , 1 | 1 = 1.

  :按位取异或( ^ ): 0 ^ 1 = 1 , 1 ^ 1 = 0 , 0 ^ 0 = 0 , 1 ^ 0 = 1.

②题面:

  有一个 W 行 H 列的广场,需要用 1*2 小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法?

  样例输入: 2 4  样例输出: 5

  

③题目解决:

  ①之前对状压DP不太了解,蒟蒻看到题面的第一眼想到的是线性递推.设F[ i ][ j ]为大小为 i * j的矩阵的铺盖方案,F[ i ][ j ]由F[ i -1][ j ],F[ i-2 ][  j  ],F[ i ][ j - 1],F[ i ][ j -2]转移而来,即在行与列上讨论竖放与横放,并且要根据行与列的奇偶性判断方案转移的合法性.蒟蒻认为DP的转移思路没错,但转移无法对状态判重,会使ans变大.

  ②在听了大佬的讲解后,蒟蒻发现很多问题本质上都是两种对立或相关连的状态构成,正好符合二进制0/1状态,对于这类问题可以用二进制串表示状态.对于这一题,我们设横放的状态为" 0 0 ",对于竖放的设上面的为' 1 ',下面的为' 0 ',显然这一行的摆放状态会影响下一行的拜访状态,所以利用行进行状态转移.

  ③怎么判断转移两个状态的合法性?首先考虑在相邻两行的同一位置肯定不为'1'.因为'1'代表竖放的上面那一格,下一个为零才行,不然就表示两个竖放的重叠了了一格,肯定不合法,我们对两个二进制串进行&运算,那么结果为1就是不合法状态.然后我们再想,' 1 '与' 1 '就算不对应,也有不合法的状态,例如上行的' 1 '就一定会占下一行的'0',在下一行一段的'0'被占后,若连续的'0'为奇数,则表示横放绝对不合法.如何表示?我们两个二进制串进行|运算,我们发现运算后的字符串中字符为'1'的情况为'0 1'或'1 0'(前面的为上,后面的为下)'0 1'则表示上面为横放的点(也可能为上一个竖放的下一个点),下面为竖放的上点显然对这一行的横放不影响.'1 0'则表示这点竖放,影响下一行,也对这一行的横放不影响.那剩下的为'0 0',表示上行横放,这一行也横放,那我们必须让连续的零为偶数才能合法匹配.

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define e exit(0)
#define R register
#define ll long long
int main()
long long W,H,num,sum,f[13][2050],check[2050];
{
    freopen("floor.in","r",stdin);
    freopen("floor.out","w",stdout);
    scanf("%lld%lld",&W,&H);
    if((W&1)&&(H&1)){
        printf("0");
        return 0;
    }
    for(R int i=0;i<(1<<H);++i){
        num=sum=0;
        for(R int j=0;j<H;++j)
            if((1<<j)&i)
                num|=sum,sum=0;
            else sum^=1;
        check[i]=num|sum ? 0: 1;
    }
    f[0][0]=1;
    for(R ll i=1;i<=W;++i)
        for(R ll j=0;j<(1<<H);++j)
        {
            f[i][j]=0;
            for(R ll k=0;k<(1<<H);++k)
                if(!(j&k)&&check[j|k])
                    f[i][j]+=f[i-1][k];
        }
    printf("%lld",f[W][0]);
    return 0;
}

④一点技巧与细节:

 ①:对于|运算后判断连续的零是否为偶数,我们可以预处理.

 ②:可能最末尾有连续的零为奇数,没有'1'去停止它,用'1'停止记数时注意.

 ③:对于语句if((1<<j)&i)是表示判断i的第j位是否为1,是一种常用技巧.

原文地址:https://www.cnblogs.com/xqysckt/p/11291051.html