hdu1069 dp动态规划

来源:互联网 发布:域名有什么商业价值 编辑:程序博客网 时间:2024/06/08 02:45

Monkey and Banana

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11287    Accepted Submission(s): 5906

Problem Description

A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, provide the monkey with some blocks. If the monkey is clever enough, it shall be able to reach the banana by placing one block on the top another to build a tower and climb up to get its favorite food.

The researchers have n types of blocks, and an unlimited supply of blocks of each type. Each type-i block was a rectangular solid with linear dimensions (xi, yi, zi). A block could be reoriented so that any two of its three dimensions determined the dimensions of the base and the other dimension was the height.

They want to make sure that the tallest tower possible by stacking blocks can reach the roof. The problem is that, in building a tower, one block could only be placed on top of another block as long as the two base dimensions of the upper block were both strictly smaller than the corresponding base dimensions of the lower block because there has to be some space for the monkey to step on. This meant, for example, that blocks oriented to have equal-sized bases couldn’t be stacked.

Your job is to write a program that determines the height of the tallest tower the monkey can build with a given set of blocks.

 

Input
The input file will contain one or more test cases. The first line of each test case contains an integer n,
representing the number of different blocks in the following data set. The maximum value for n is 30.
Each of the next n lines contains three integers representing the values xi, yi and zi.
Input is terminated by a value of zero (0) for n.

 

Output
For each test case, print one line containing the case number (they are numbered sequentially starting from 1) and the height of the tallest possible tower in the format “Case case: maximum height = height”.

 

Sample Input
1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0

 

Sample Output
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342

 

题目大致的意思:

有一群人, 闲着没事研究猴子的智商, 把香蕉挂屋顶上, 然后给猴子一些盒子, 问这些盒子最高能叠多高.

a盒子要叠在b盒子的条件是a盒子的底面严格大于b盒子的底面,

即 a.x> b.x && a.y>b.y

或者 a.x>b.y && a.y>b.x

盒子是长方体的, 有长 宽 高, 但是可以随便放. 横放, 坚着放, 横着放. 排列一下也就是有6种情况.

每种盒子的数量是无限的.

输入输出说明:

输入包含多个测试用例, 每个用例由n+1行组成, 第1行说明盒子的种数, 第n到n+1行, 每一行说明一种盒子的长宽高

注意下输入规模, 最多才30种盒子.

我一开始做这个题目的时候, 想的是贪心, 既然跟长宽高有关, 那就把每个盒子的6种情况放到一个结构体数组中,然后排序一下, 然后贪心一下.

要看AC代码直接拉到文章最底部.

大致的代码如下(非AC代码):

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> using namespace std;struct box{    int x,y,z;};box f[200];//30*6bool xmp(box a, box b){    if(a.x!=b.x)        return a.x>b.x;    if(a.y!=b.y)        return a.y>b.y;    return a.z>b.z;}int main(){    int n,i,j,a,b,c,cnt,maxx,cse=1;    freopen("hdu1069.in", "r", stdin);    while(~scanf("%d", &n) &&n){        cnt=0;        memset(f, 0, sizeof(f));        for(i=0;i<n;i++){            scanf("%d%d%d", &a, &b, &c);            if(a==b &&a==c){                f[cnt].x=a;                f[cnt].y=b;                f[cnt].z=c;                cnt++;            }else{                f[cnt].x=a;f[cnt].y=b;f[cnt].z=c;cnt++;                f[cnt].x=a;f[cnt].y=c;f[cnt].z=b;cnt++;                f[cnt].x=b;f[cnt].y=a;f[cnt].z=c;cnt++;                f[cnt].x=b;f[cnt].y=c;f[cnt].z=a;cnt++;                f[cnt].x=c;f[cnt].y=b;f[cnt].z=a;cnt++;                f[cnt].x=c;f[cnt].y=a;f[cnt].z=b;cnt++;            }        }        sort(f,f+cnt,xmp);        maxx=-1;        for(i=0;i<cnt;i++){            int sum=f[i].z;            int pre=i;            for(j=i+1;j<cnt;j++){                if(f[j].x<f[pre].x && f[j].y<f[pre].y){                    //这里贪心了, 尽量多套几个盒子                    sum+=f[j].z;                    pre=j;                }            }            maxx=max(maxx, sum);        }        printf("Case %d: maximum height = %d\n", cse, maxx);        cse++;    }    return 0;}


然后开始改进, 还是贪心, 既然贪心最多盒子数不行, 那我在盒子高度上贪心呢?

for(i=0;i<cnt;i++){            int sum=f[i].z;            int pre=i;            int mini=-1;            for(;;){                mini=-1;                k=-1;                for(j=pre+1;j<cnt;j++){                    if(f[j].x<f[pre].x && f[j].y<f[pre].y && f[j].z>mini){                        mini=f[j].z;                        k=j;                    }                }                if(-1==k)break;                sum+=mini;                pre=k;            }             maxx=max(maxx, sum);        }


很惨, 还是过不了题目给的最后一个测试用例, 想了下, 确实, 这样贪心不能得到最优解.可能先套了个高度很小的盒子, 然后后面又套了高度大的盒子, 然后总高度更高.

贪心不行就上动态规划了, 哼.

很容易想到的状态转移方程:

dp[x][y] = max( dp[x][y],  dp[i][j] + f[x][y].z); //其中i<x, j<y

dp[x][y]表示 长为x,宽为y的盒子做最底下一个时, 能叠出的最大高度

i<x, j<y所以 x,y 是比i,j 更大的盒子, 所以小盒子的最大高度加上大盒子的高度, 就是大盒子的最大高度

当然了, 这个转移方程还得改, 谁晓得他的x是不是10^9之类的数, 总不能开那么大的数组吧.

既然之前已经把盒子排序了, 所以 [0, cnt) 这些盒子的底面是越来越小的.

所以 i 肯定比 i+1 这个盒子大(非严格大).

所以伪代码如下:

for i=cnt-1 to 0    dp[i] = f[i].z    for j=i+1 to cnt-1        if j盒子严格小于i盒子            dp[i]=max(dp[i], dp[j]+ f[i].z)


最后, 附上AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> using namespace std;struct box{    int x,y,z;};box f[200];//30*6int dp[200];bool xmp(box a, box b){    if(a.x!=b.x)        return a.x>b.x;    if(a.y!=b.y)        return a.y>b.y;    return a.z>b.z;}int main(){    int n,i,j,a,b,c,cnt,maxx,cse=1,k;    //freopen("hdu1069.in", "r", stdin);    while(~scanf("%d", &n) &&n){        cnt=0;        memset(f, 0, sizeof(f));        for(i=0;i<n;i++){            scanf("%d%d%d", &a, &b, &c);            if(a==b &&a==c){                f[cnt].x=a;                f[cnt].y=b;                f[cnt].z=c;                cnt++;            }else{                f[cnt].x=a;f[cnt].y=b;f[cnt].z=c;cnt++;                f[cnt].x=a;f[cnt].y=c;f[cnt].z=b;cnt++;                f[cnt].x=b;f[cnt].y=a;f[cnt].z=c;cnt++;                f[cnt].x=b;f[cnt].y=c;f[cnt].z=a;cnt++;                f[cnt].x=c;f[cnt].y=b;f[cnt].z=a;cnt++;                f[cnt].x=c;f[cnt].y=a;f[cnt].z=b;cnt++;            }        }        sort(f,f+cnt,xmp);        maxx=-1;        for(i=cnt-1;i>=0;i--){            dp[i]=f[i].z;            for(j=i+1;j<cnt;j++){                if(f[i].x>f[j].x && f[i].y>f[j].y)                    dp[i]=max(dp[i], dp[j]+f[i].z);            }            maxx=max(dp[i], maxx);        }        printf("Case %d: maximum height = %d\n", cse, maxx);        cse++;    }    return 0;}


1 0
原创粉丝点击