ZOJ 1100 Mondriaan's Dream

来源:互联网 发布:mysql 5.7.15安装图解 编辑:程序博客网 时间:2024/04/29 21:24
解题报告没看懂,先存
/*
这至少是一道中等难度的动态规划题目,首先用面积
的奇偶性,当高度和宽度都为奇数时显然答案为0;
其次,把每一列的砖块压缩为二进制编码,搜索上一
列到当前列的状态转化是否能够达到,接着DP;
对于每一个位置,我们有三种放置方法:
1.水平放置
2.竖直放置
3.不放置
4. n为当行的位置,初始化n, from, to都为0;对应以
上三种放置方法,from, to的调整为:
1. n = n + 2, from=(from*2+1)*2+1=from*4+3, to=to*4+3;
2. n = n + 1, from=from*2+1, to=to*2 (即不放置);
3. n = n + 1, from=from*2, to=to*2+1 (即竖直放置);

上图to值编码a1=((((3*2+1)*4+3)*4+3))*2*2)*4+3=2035<=2^11-1;

上图from值编码a0=((((((1*2+1)*2+1)*2+1)*4+3)*2+1)*2*2)*4+3=2035<=2^11-1;
图1的to值等于图2的from值,这样就能匹配DP了。
*/
/*
**************************************************
ZOJ 1100 Mondriaan's Dream
Tips: DP 'double'
memory 292K
runtime 0MS
3WA 1AC
Accepted time 2009-02-21 11:55:36
**************************************************
*/
#include<iostream>
#include<string>
using namespace std;
int a[2][10000],w,h,loop;
//int b[2][2050];
double b[2][2050];
void dfs(int n, int from, int to){
    if(n>h) return;
    if(n==h){
        a[0][loop]=from;
        a[1][loop]=to;
        loop++;
        return;
    }
    dfs(n+2,from<<2|3,to<<2|3);
    dfs(n+1,from<<1|1,to<<1);
    dfs(n+1,from<<1,to<<1|1);
}
void dp(){
    int i,j;
    memset(b,0,sizeof(b));
    b[0][(1<<h)-1]=1;
    for(i=0;i<w;i++){
        for(j=0;j<loop;j++){
            b[(i+1)%2][a[1][j]]+=b[i%2][a[0][j]];
        }
        memset(b[i%2],0,sizeof(b[0]));
    }
}
int main(){
    while(scanf("%d%d",&h,&w)!=EOF){
        if(h==0 && w==0) break;
        if((w*h)%2){
            printf("0\n");
            continue;
        }
        if(h>w){
            h=h^w;w=w^h;h=h^w;
        }
        loop=0;
        dfs(0,0,0);
        dp();
        printf("%.0lf\n",b[w%2][(1<<h)-1]);
    }
    return 0;
}
/*
这又是个经典的DP问题,但是下面的算法源自组合数学。
用1*2的砖铺满一个n*m的房间,有多少种方法?
在网上搜到一个国外数学家的论文,找到一个公式,
详细见Statistical Mechanics of Dimers on a Plane Lattice
具体公式
for(i,1......【n/2】)
for(j,1.......【m/2】)
       result*=4cos(pi+i/(h+1))^2+4cos(pi+j/(w+1))^2;
注意 result的初始值为1,【】表示向下取整,pi要尽量精确
最后的结果去整数部分就是答案
另外按照“面积守恒定理”房间面积为奇数的肯定没办法铺满;
*/

/*
*********************************************
ZOJ 1100 Mondriaan's Dream
Tips: math
memory 184K
runtime 0MS
1AC
Accepted time 2009-02-21 21:26:41
*********************************************
*/
#include <cstdlib>
#include <iostream>
#include <cmath>
#define Pi 2*acos(0)
using namespace std;
int h,w,endh,endw;
double result;
int main(){
    while(scanf("%d%d",&h,&w)!=EOF){
        if(h==0 && w==0) break;
        if(h*w%2){
           printf("0\n");
           continue;
        }
        result=1.0;
        endh=h/2;
        endw=w/2;
        for(int i=1;i<=endh;++i){
           for(int j=1;j<=endw;++j){
                result*=4*(pow(cos(Pi*i/(h+1.0)),2.0)+pow(cos(Pi*j/(w+1.0)),2.0)); 
           }
        }
        printf("%0.0f\n",result);
    }
    return 0;
}
0 0
原创粉丝点击