smoj1710:砖块II (dp套dp)

来源:互联网 发布:淘宝物流评价怎么修改 编辑:程序博客网 时间:2024/05/16 04:08

砖块II

题目描述

有K种不同规则的长方体砖块,长宽高分别是:1×1×1、2×1×1、3×1×1…,K×1×1.还给出一个W×1×1的地基,如下图所示,W=9, k=3,下面的是地基:


现在你要在地基上堆放砖块,必须满足如下的规则:
1、 砖块只能横放,不能竖放。
2、 砖块必须放置在整数位置,且不能越出地基。
3、 砖块任何部分的正下方都必须要有其他砖块或者是地基。
例如:下图是不合法的放置方式,有4个不合法的地方:


我们定义一种堆放砖块方案的高度height:它是指该方案中最高的砖块是第几层,其中地基是第0层,例如(图二)的高度是3。
我们定义不同的堆放方案:例如有两种堆放方案A和B,只要满足两个条件之一,方案A和方案B就是不同的方案:
1、 在某个位置方案A有砖块而方案B在该位置没有砖块,或者方案B有砖块而方案A没有。
2、 在某个位置方案A和方案B都有砖块,但是它们不是同一种规格的砖块。
给定地基的长度W,和地砖的最大长度K,你的任务是计算有多少种不同的堆放砖块的方案,你的堆放砖块方案的高度height不能超过给定的H。答案模1000000007。
例如:下图是W=3, k=3, H=2的所有合法方案:


输入格式 1710.in

多组测试数据。
第一行,一个整数G,表示有G组测试数据。1 <= G <=3。
每组测试数据格式如下: 
一行,三个整数W、H、K 。1 <= W, H <= 50。 1 <= K <= W

输出格式 1710.out

共G行,每行一个整数。

输入样例 1710.in

3
3 1 3
3 2 3
10 10 3

输出样例 1710.out

13
83
288535435

题目分析:这题其实不算难,然而我考试的时候还是没想出来。感觉自己数据结构题做多了,思维好像有点退化……。我们先看原问题:地基长度为W,高度限制为H,记为f(W,H)。然后我们考虑一层一层地铺。对于最下面一层,如果全部铺满,问题就变成了f(W,H-1)。我们求出f(W,H-1)后并不是直接加进f(W,H)的答案中,因为下面这一层长度为W的连续一段,又有很多种铺法,我们记为dp[W]。根据乘法原理,我们将f(W,H-1)*dp[W]加进f(W,H)中,而我们知道dp[W]又可以通过预处理一个DP来求。那么假设最下面一层没有铺满呢?那么这一层必定有一个最右边的空格子,假设它在第i个位置。由于他已经是最右的空格子,故它右边一定是连续的一段。类似上面的推导过程,右边可能的铺法有f(W-i,H-1)*dp[W-i]种,而左边就转化为了子问题f(i-1,H)。我们枚举i,然后把f(i-1,H)*f(W-i,H-1)*dp[W-i]加进f(W,H)里即可。



在这里要注意一下边界的处理:由于我们用的是乘法原理,所以dp[0],f[i][0],f[0][i]都要初始化为1。

CODE:

#include<iostream>#include<string>#include<cstring>#include<cmath>#include<cstdio>#include<cstdlib>#include<stdio.h>#include<algorithm>using namespace std;const int maxn=55;const long long M=1000000007;typedef long long LL;LL dp[maxn];LL f[maxn][maxn];int G,W,H,K;int main(){freopen("b.in","r",stdin);freopen("b.out","w",stdout);scanf("%d",&G);while (G--){scanf("%d%d%d",&W,&H,&K);memset(dp,0,sizeof(dp));memset(f,0,sizeof(f));dp[0]=1;for (int i=1; i<=W; i++){dp[i]=0;for (int j=1; j<=min(i,K); j++) dp[i]=(dp[i]+dp[i-j])%M;}for (int i=0; i<=W; i++) f[0][i]=1;for (int i=1; i<=H; i++) f[i][0]=1;for (int i=1; i<=H; i++)for (int len=1; len<=W; len++){f[i][len]=f[i-1][len]*dp[len]%M;for (int j=1; j<=len; j++)f[i][len]=(f[i][len]+f[i-1][j-1]*f[i][len-j]%M*dp[j-1]%M)%M;}cout<<f[H][W]<<endl;}return 0;}