zoukankan      html  css  js  c++  java
  • poj2411(状压dp)

    Mondriaan's Dream
    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 22150   Accepted: 12398

    Description

    Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways. 

    Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!

    Input

    The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.

    Output

    For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.

    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
    

    Source

    这题一开始用爆搜,发现最大就只能跑7*10的,再大答案都出不来了…………。
    后来发现是状压dp,索性就看了看怎么写的。
    直接上篇博客吧,毕竟感觉自己也写不出这么详细(嫌麻烦!!)
    博客的方法交了后发现视乎有点慢,后来又发现另一种方法,要快很多,但是没有详细解释,所以我打算讲讲这个代码。
    直接看代码吧,解释都写注释里了。
     1 #include<cstdio>
     2 #include<string.h>
     3 #include<iostream>
     4 using namespace std;
     5 typedef long long ll;
     6 int N,M;
     7 ll allsta;
     8 ll dp[12][(1<<12)];///dp[i][j]=k第i行的第j状态下有k种方法
     9 bool init[(1<<12)];///这里是个优化,处理出一行中的所有状态是否合法
    10 bool check(ll a,ll b){
    11     if((a|b)!=allsta-1) return false;///(a|b如果不等于tt-1就意味着两行有上下两个格子都为0,而这种情况是不可能的)
    12     ll k=(a&b);///(a&b是两行的这个状态下的上下都为1后的状态是否合法,至于为什么可以这样,是因为init中存着一行中所有的情况是否合法)
    13     return init[k];
    14 }
    15 void Init(){
    16     memset(init,true,sizeof(init));///初始化全部合法
    17     for(ll i=0;i<(1<<11);i++){
    18         bool flag=false;
    19         ll x=i;
    20         while(x){///这个模拟一下就知道了
    21         ///因为只有横着贴/竖着贴,所以如果横着贴,那它和它下一位都必须为1,
    22             if(x&1){
    23                 flag=!flag;///这个操作保证了它和它下一位必须为1
    24             }else if(flag){///上一位为1,这一位为0,则这个状态不合法(横着贴)
    25                 init[i]=false;
    26                 break;
    27             }
    28             x>>=1;
    29         }
    30         if(flag) init[i]=false;///这个是最后一位不能为1(即不可能贴出外面去)
    31     }
    32 }
    33 int main(){
    34     Init();
    35     while(scanf("%d%d",&N,&M)!=EOF&&N&&M){
    36         if(N*M%2){
    37             printf("0
    ");
    38             continue;
    39         }
    40         memset(dp,0,sizeof(dp));
    41         if(N<M) swap(N,M);///优化,让状态数减少
    42         allsta=(1<<M);
    43         for(int i=0;i<allsta;i++){
    44             if(init[i]){
    45                 dp[0][i]=1;
    46             }
    47         }
    48         for(int i=1;i<N;i++){
    49             for(ll j=0;j<allsta;j++){
    50                 for(ll k=0;k<allsta;k++){
    51                     if(check(j,k)){///状态转移
    52                         dp[i][j]+=dp[i-1][k];
    53                     }
    54                 }
    55             }
    56         }
    57         printf("%lld
    ",dp[N-1][allsta-1]);
    58     }
    59     return 0;
    60 }
    View Code
  • 相关阅读:
    java基本数据类型及运算的注意事项
    B-Tree 和 B+Tree 结构及应用,InnoDB 引擎, MyISAM 引擎
    软件工程与软件开发模型、软件开发方法
    2020年3月份Unity3D游戏源码合集-免费下载
    独立游戏开发必备!8个效果不错的Unity3D 免费模型资源包
    2019年4月份整理的Unity3D 20个实用插件-免费下载
    2019年4月份整理的Unity3D游戏完整源码
    2019年3月整理的2D美术资源合集
    画面效果都不错!20个精品Unity3D着色器插件
    Unity3D中UnityPlayerActivity与UnityPlayerNativeActivity有什么区别
  • 原文地址:https://www.cnblogs.com/liuzuolin/p/10908021.html
Copyright © 2011-2022 走看看