HLOJ491 壮压例题5广场铺砖

题面

题目描述
有一个W行H列的广场,需要用1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法?
输入格式
只有一行2个整数,分别为W和H,(1<=W,H<=11)
输出格式
只有1个整数,为所有的铺法数。
样例数据
input
2 4
output
5

题解

经典状态压缩例题。h位二进制数代表某一行的状态:1代表是竖砖的上半部分,0代表其他情况。
所以状态 f [ i ] [ j ] 代表第i行的情况为j的时候,前i行的方案数
观察题目,我们发现只有i-1行能够对i行进行转移。
设j为第i行要转移的状态,k是第i-1行的状态。
f[i-1][k]能转移到f[i][j]的条件是:
首先k和l都合法。
其次,k&l==0
最后,k|l也要是合法的状态。否则在竖块之间插入不了横块。

所以我们先预处理出所有可能的状态放进集合S。
可能的状态满足:两个相邻的1之间的0的个数是偶数。
那么状态转移方程:
f [ i ] [ j ] = f [ i 1 ] [ k ]         i n _ s [ j | k ]   j|k==0

code

#include<bits/stdc++.h>
using namespace std;
inline long long read(){
    long long num=0;
    char c=' ';
    bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-')
    flag=false;
    for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
    return flag ? num : -num;
}
const int maxn=13;
long long n,m,f[maxn][1<<maxn];
bool in_s[1<<maxn];
void yuchuli(){
    for(int i=0;i<1<<m;i++){
        bool incorrect=0,count=0;
        for(int j=0;j<m;j++)
            if(i>>j&1)incorrect|=count,count=0;
                else count^=1;
        in_s[i]=count|incorrect ? 0 : 1;
    }
}
void dp(){
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<1<<m;j++){
            f[i][j]=0;
            for(int k=0;k<1<<m;k++){
                if((j&k)==0&&in_s[j|k])
                    f[i][j]+=f[i-1][k];
            }
        }
    }
}
int main(){
    n=read();m=read();
    yuchuli();
    dp();
    printf("%lld\n",f[n][0]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39670434/article/details/80313623
今日推荐