zoj 1100 - Mondriaan's Dream

题目:在m*n的地板上铺上相同的1*2的地板砖,问有多少种铺法。

分析:dp,组合,计数。经典dp问题,状态压缩。

状态:设f(i,j)为前i-1行铺满,第i行铺的状态的位表示为j时的铺砖种类数;

转移:因为只能横铺或者竖铺,那么一个砖块铺之前的状态只有两种;

且如果当前竖放会对下一行产生影响,建立相邻两行状态对应关系;

这里利用dfs找到所有f(i,j)的上一行的所有前置状态f(i-1,k)加和即可;

f(i,j)= sum(f(i-1,k)){ 其中,f(i-1,k)可以产生f(i,j)状态 };

(大黄的三维DP实现简单,效率较差。)

组合学公式 :π(4cos(pi+i/(h+1))^2+4cos(pi+j/(w+1))^2) { 1<=i<=h/2,1<=j<=w/2 }。

说明:纠结N久最后发现%I64d一直WA。%lld就过了。(2011-09-27 19:15)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node
{
    int s,l;
}seg;
seg S[ 10 ];

long long F[ 12 ][ 1<<11 ];

int  V[ 1<<11 ][ 99 ];
int  Count[ 1<<11 ];

//用dfs找到可以到达的状态
void dfs( int A, int B, int C )
{
    if ( !A ) {
        V[ C ][ ++ Count[ C ] ] = B;
        return;
    }else {
        int V = A&-A;//取得最后一个 1的位置
        dfs( A&~V, B&~V, C );
        if ( A&(V<<1) ) dfs( A&~(3*V), B, C );
    }
}

int main()
{
    int n,m;
    while ( scanf("%d%d",&n,&m) != EOF && m ) {

        if ( n%2&&m%2 ) {printf("0\n");continue;}
        if ( m>n ) {int t = m;m = n;n = t;}

        int M = (1<<m)-1;
        for ( int i = 0 ; i <= M ; ++ i ) {
            Count[ i ] = 0;
            dfs( i, M, i );
        }

        for ( int i = 0 ; i <= n ; ++ i )
        for ( int j = 0 ; j <= M ; ++ j )
            F[ i ][ j ] = 0LL;
        F[ 0 ][ M ] = 1LL;

        for ( int i = 1 ; i <= n ; ++ i )
        for ( int j = M ; j >= 0 ; -- j )
        for ( int k = Count[ j ] ; k >= 1 ; -- k )
            F[ i ][ j ] += F[ i-1 ][ V[ j ][ k ] ];

        printf("%lld\n",F[ n ][ M ]);
    }
    return 0;
}

zoj 1100 - Mondriaan's Dream

时间: 2024-07-30 16:36:07

zoj 1100 - Mondriaan's Dream的相关文章

zoj 1100 - Mondriaan&amp;#39;s Dream

题目:在m*n的地板上铺上同样的1*2的地板砖,问有多少种铺法. 分析:dp,组合,计数.经典dp问题,状态压缩. 状态:设f(i,j)为前i-1行铺满,第i行铺的状态的位表示为j时的铺砖种类数: 转移:由于仅仅能横铺或者竖铺.那么一个砖块铺之前的状态仅仅有两种: 且假设当前竖放会对下一行产生影响,建立相邻两行状态相应关系. 这里利用dfs找到全部f(i.j)的上一行的全部前置状态f(i-1,k)加和就可以. f(i.j)= sum(f(i-1,k)){ 当中,f(i-1,k)能够产生f(i.j

POJ 2411 Mondriaan&#39;s Dream (状压DP)

题意:给出一个n*m的棋盘,及一个小的矩形1*2,问用这个小的矩形将这个大的棋盘覆盖有多少种方法. 析:对第(i,j)位置,要么不放,要么竖着放,要么横着放,如果竖着放,我们记第 (i,j)位置为0,(i+1,j)为1,如果横着放,那么我们记 (i,j),(i,j+1)都为1,然后dp[i][s]表示 第 i 行状态为 s 时,有多少方法,那么我们就可以考虑与和匹配的状态,这个也很容易判断. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

POJ 2411 Mondriaan&#39;s Dream(状态压缩+深搜)

每一行的填充仅与上一行有关系,每行的目的都是至少填充满上一行. 当填充到i行的时候,i-1行某列没填充必须用竖直的方格填充,这是固定的,剩下其余的则搜索填充. 用2进制的01表示不放还是放 第i行只和i-1行有关 枚举i-1行的每个状态,推出由此状态能达到的i行状态 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态. 然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,

POJ2411(Mondriaan&#39;s Dream)

题目链接:传送门 题目大意:用1*2大小的砖块去铺满n*m大小的地面,有多少种方案 题目思路:因为1<=n,m<=11,并且砖块是1*2,故可以用二进制思想,也就是状态压缩DP,其中矩阵中为0的元素表示当前位置竖着放一块砖,而连着 两个1表示横着放一块砖(状态压缩真的很奇妙) #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

POJ 2411 Mondriaan&#39;s Dream

题目链接:http://poj.org/problem?id=2411 状态压缩Dynamic Programming. For each row, at ith position, 1 means that there is a block placed at this row and next row (vertically). otherwise, its 0. For the example in question, the state of For the example in que

【poj2411】 Mondriaan&#39;s Dream

http://poj.org/problem?id=2411 (题目链接) 题意 一个$n*m$的网格,用$1*2$的方块填满有多少种方案. Solution 轮廓线dp板子.按格dp,对上方和左方的格子的占用情况进行讨论转移.0表示已放置,1表示未放置. 细节 LL,滚动清空数组. 代码 // poj2411 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring>

poj 2411 Mondriaan&#39;s Dream(状态压缩+dp)

 题意:用1*2砖块铺满n*m的房间. 思路转自:http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html 因为这道题输入范围在11*11之间,所以可以先打表直接输出.......... 状态压缩DP 经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案 其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int