• poj2411 Mondriaan's Dream 题解报告


    题目传送门

    【题目大意】

    往一个$N*M$的矩阵中放$1*2$的小长方形,可以横着放也可以竖着放,不能重叠,求把大矩阵填满有多少种方案。

    【思路分析】

    我们对每一行单独分析,对于第$i$行中的第$j$格,可能有一下三种状态:

    1.是一个横着放的小长方形的其中一格

    2.是竖着放的小长方形的下面一格

    3.是竖着放的小长方形的上面一格

    对于第1、2种状态可以直接处理,而第3种状态会对下面一行形成影响,即第$i+1$行第$j$格不能放小长方形,这种状态要单独考虑。

    我们选择用一个$M$位的二进制数来记录每一行的状态,其中如果第$j$位为1,则表示这是上面的第3种状态;如果为0,则是1、2种状态。

    设$f[i][j]$表示第$i$行状态为$j$时,前$i$行的总方案数。

    第$i-1$行的状态$k$能转移到第$i$行的状态$j$,当且仅当:

    1.$j$和$k$执行按位与运算的结果为0,这保证了$k$中每个数字1下方为0,即第2种状态。

    2.$j$和$k$执行按位或运算的结果的二进制表示中,每一段连续的0都必须是偶数个,这些0代表的是若干个横着的小长方形。

    我们预处理出$[0,2^M-1]$内所有满足“二进制表示下每一段连续的0都有偶数个”的整数,记录在集合$S$中,则

    $$f[i][j]=sum_{j&k=0且j|k in S}f[i-1][k]$$

    初始值:$f[0][0]=1$,其余均为0

    目标:$f[N][0]$

    时间复杂度:$O(4^MN)$

    【代码实现】

     1 #include<iostream>
     2 #include<cstring>
     3 #define ll long long
     4 #define rg register
     5 #define go(i,a,b) for(rg int i=a;i<=b;i++)
     6 using namespace std;
     7 int n,m;
     8 ll f[12][1<<11];
     9 bool ready[1<<11];
    10 int main(){
    11     while(cin>>n>>m&&n){
    12         go(i,0,(1<<m)-1){//预处理
    13             bool t=0,k=0;
    14             go(j,0,m-1)
    15                 if(i>>j&1) k|=t,t=0;
    16                 else t^=1;
    17             ready[i]=k|t?0:1;
    18         }
    19         f[0][0]=1;
    20         go(i,1,n) go(j,0,(1<<m)-1){
    21             f[i][j]=0;
    22             go(k,0,(1<<m)-1)
    23                 if((j&k)==0&&ready[j|k]) f[i][j]+=f[i-1][k];
    24         }
    25         cout<<f[n][0]<<endl;
    26     }
    27     return 0;
    28 }
    代码戳这里
  • 相关阅读:
    Excel 如何复制粘贴一整行
    如何修改文件的扩展名(后缀)
    中文乱码之myEclipse项目导入时中文乱码(待)
    如何在java中导入jar包
    如何在myEclipse中创建配置文件,比如:XXX.properties
    Postman安装教程
    API是什么?——回答:接口。(待)
    找回J2EE 之再学习打卡记录
    让外界可以访问电脑上的网站的几种方式——花生壳,域名,IIS(待)
    18、任务暂停挂起
  • 原文地址:https://www.cnblogs.com/THWZF/p/11226784.html
Copyright © 2020-2023  润新知