zoukankan      html  css  js  c++  java
  • Mondriaan's Dream【状压DP】

    测评传送门

    题意:

    给定一个 n*m 的矩形,用1*2的方块填充的所有方案数

     

     

    Sample Input

    1 2
    1 3
    1 4
    2 2
    2 3
    2 4
    2 11
    4 11
    0 0
    

    Sample Output

    1
    0
    1
    2
    3
    5
    144
    51205

    思路:

    像这样看上去就不会做的题目数据范围一般都不大(因为要用状压呀,大了能存的下吗?) 

    而且显然答案会很大,所以记得开 long long 

    正题----

    我们可以一行一行地看,对于上一行地情况,可以是横着的也可以是竖着的,横着的对我们当前这一行的状态无影响,关键是竖着的方块我们在这一行必须给它接上。

    我们用长度为 m 的二进制数来表示状态

      状态为竖着摆时的上半截,状态为 1 ,否则为 0

    我们考虑当前这一行,如果上一行是1,我必须接上下半截,状态为 0 ;如果是 0 ,那我这一行就可以随便摆 

    设当前状态为 j,上一行状态为 k

    所以必定满足:

    1. j&k==0
    2. j | k 状态中连续的 0 必须有偶数个

    第二条也很显然,我们或下来的是什么状态呢?1表示竖着,0,表示横着且连续,如果 0 是奇数个,就不符合要求

    所以我们就先需要预处理出合法的情况

    code

    #include<stdio.h> 
    #include<algorithm> 
    using namespace std;
    int n,m;
    long long f[12][1<<11];
    bool ins[1<<11];
    
    int main() 
    {
        while(scanf("%d%d",&n,&m) && n && m) {
            int mix=(1<<m);
            for(int i=0;i<mix;++i) {
                bool cnt=0,flag=0;
                for(int j=0;j<m;++j) {
                    if(i>>j & 1) flag|=cnt,cnt=0;
                    else cnt^=1;
                }
                ins[i]=flag|cnt?0:1;
            }
            f[0][0]=1;
            for(int i=1;i<=n;++i) {
                for(int j=0;j<mix;++j) {
                    f[i][j]=0;
                    for(int k=0;k<mix;++k) {
                        if((j&k)==0 && ins[j|k])
                            f[i][j]+=f[i-1][k];
                    }
                }
            }
            printf("%lld
    ",f[n][0]);
        }
        return 0;
    }
  • 相关阅读:
    谁记录了mysql error log中的超长信息(记pt-stalk一个bug的定位过程)
    谈谈MySQL无法连接的原因和分析方法
    MySQL 5.7基于GTID复制的常见问题和修复步骤(二)
    日常运维故障记录和解决
    python学习之-- 故障记录汇总
    sshpass-Linux命令之非交互SSH密码验证
    python 之 线程池实现并发
    python 之 实现su 到root账号
    shell
    shell
  • 原文地址:https://www.cnblogs.com/qseer/p/9904356.html
Copyright © 2011-2022 走看看