1. 程式人生 > >Monkey and Banana

Monkey and Banana

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

題意:給你n個長方體以及每個的長寬高,這些長方體的數量無限且可以任意旋轉。長方體可以疊放在長和寬都比它大的長方體上(不能都相等),問最高能疊多高。

思路

(1)輸入問題;這不是普通的輸入,因為一個長方體可以用多次

但是實際上最多用3次   6個面兩兩重複(其實剛開始我還寫的兩個,因為我覺得 一個長方體最大面和最小面能用一下,另一個面和最大面,最小面有一邊相等,這樣想是錯誤的)

(2)這樣一個長方體變成3個長方體,選長方體使其最高,乍一看像揹包,一件物品選或者不選,但是,天真的我忘了一點,揹包選物品是沒有順序,這個物品可以放在最後判斷選不選,也可以放在前面,但是這題不一樣,先選和後選是不一樣的,先選可能能選上,但是後選就不一定能不能選上了,這一點差別導致思想千差萬別

 (3)既然要取最大值,那麼最好還是把最大的放後面,這樣我們從頭開始找(你是不是想到了貪心),但是貪心是做不好這道題的,

如果遇到相同的長(或者寬),那麼你要選擇哪一個?而且即使選擇了最高的(假設是第一個,沒選的是第二個),你能保證下一次不會出一個寬(或者長)比第一個長,比第二個短,而且高特別高;那麼只能動態規劃了,動態規劃會記錄前面所有的情況的最優解,用前面的多個選一個推出下一個,貪心只能用最近的一個推下一個

這就是動規和貪心的本質區別

這是我思考的思路,寫出來供大家思考

下面是題的思路

(1)先輸入後,一個變6個,然後排一下序,從大到小(這樣方便)

(2)然後就是  最長單調遞減子序列

那麼為什麼會聯絡到最長單調遞減子序列那?

對,我們排序後,長方體都從小到大排好序了,我們要找最高,那麼其實我們就是把單調遞減子序列的 最多,換成了最高,

下面分析一下最長單調遞減子序列的動態

其實說簡單點就一句話;

從頭開始遍歷,每遍歷一個,找找前面的,有沒有比這個大的,如果有,那麼找出一個結果最大的(即最優解) 以這個為上一個狀態,在這個狀態上加上當前的值,就是當前的最優解;

C++版本一

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int t;
int n,ant;
int maxh;
int x,y,z;
struct shape{
    int l,w,h;

}a[200];

bool cmp(shape a,shape b)
{
	if (a.l == b.l)
		return a.w > b.w;
	return a.l > b.l;
}

void PushUp(int t1,int t2,int t3)
{
	a[ant].h = t3;
	a[ant].l = t1;
	a[ant].w = t2;
	ant++;
	a[ant].h = t3;
	a[ant].l = t2;
	a[ant].w = t1;
	ant++;
	a[ant].h = t2;
	a[ant].l = t1;
	a[ant].w = t3;
	ant++;
	a[ant].h = t2;
	a[ant].l = t3;
	a[ant].w = t1;
	ant++;
	a[ant].h = t1;
	a[ant].l = t2;
	a[ant].w = t3;
	ant++;
	a[ant].h = t1;
	a[ant].l = t3;
	a[ant].w = t2;
	ant++;
}

int main()
{   t=0;
    while(scanf("%d",&n)!=EOF){
        if(n==0)    break;
        t++;
        maxh=0;
        ant=1;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&x,&y,&z);
            PushUp(x,y,z);
        }
        sort(a+1,a+6*n+1,cmp);
        int dp[200];
        int ans=0;
        for(int i=1;i<=6*n;i++){
             dp[i]=a[i].h;
            for(int j=i-1;j>=0;j--){
                if(a[i].l<a[j].l&&a[i].w<a[j].w){
                    dp[i]=max(dp[i],dp[j]+a[i].h);
                }
            }
            ans=max(dp[i],ans);
        }
        printf("Case %d: maximum height = %d\n",t,ans);

    }

    //cout << "Hello world!" << endl;
    return 0;
}

C++版本二

/*
HDU1069Monkey and Banana
題目:給出一些長方體,然後讓你把他堆成塔,
要求下面的塔的要比上面的塔大(長和寬),
而且每一種長方體的數量都是無限的。

此題目考察到動態規劃裡的最長有序子序列,

*/
#include<stdio.h>
#include<algorithm>
const int MAXN=200;
using namespace std;
struct Block
{
    int x,y,high;
    int dp;//該箱子在最下面時的最大高度 
}b[MAXN];

bool cmp(Block a,Block b)//用sort函式排序,先按x後按y升序
{
    if(a.x<b.x) return 1;
    else if(a.x==b.x&&a.y<b.y)  return 1;
    else return 0;
}        
int main()
{
    int n,i,x,y,z,j,k;
    int iCase=0;
    while(scanf("%d",&n),n)
    {
        iCase++;
        k=0;
        while(n--)
        {
            scanf("%d%d%d",&x,&y,&z);
            //把給出的block放置的所有可能放進block[]中,這樣就可以解決有無限塊的問題
            if(x==y)
            {
                if(y==z)//三個相等,放一個就夠了
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                }
                else  //x==y!=z時三种放法
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=y;b[k].high=x;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                }                         
            }
            else
            {
                if(y==z)//三种放法
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                } 
                else if(x==z)
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=x;b[k].y=z;b[k].high=y;b[k].dp=b[k].high;k++;
                }  
                else//三個不等6种放法 
                {
                    b[k].x=x;b[k].y=y;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=x;b[k].high=z;b[k].dp=b[k].high;k++;
                    b[k].x=x;b[k].y=z;b[k].high=y;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=x;b[k].high=y;b[k].dp=b[k].high;k++;
                    b[k].x=y;b[k].y=z;b[k].high=x;b[k].dp=b[k].high;k++;
                    b[k].x=z;b[k].y=y;b[k].high=x;b[k].dp=b[k].high;k++;
                }          
            }        
        } 
        sort(b,b+k,cmp);
        int maxh=0;
        for(i=1;i<k;i++)
        {
            for(j=0;j<i;j++)
               if(b[i].x>b[j].x&&b[i].y>b[j].y)
                  b[i].dp=max(b[j].dp+b[i].high,b[i].dp);
            if(b[i].dp>maxh)maxh=b[i].dp;
        } 
        printf("Case %d: maximum height = %d\n",iCase,maxh);      
    }  
    return 0;  
}

C++版本三

#include<cstdio>
#include<algorithm>
using namespace std;
struct stu
{
    int l,w,h;
}st[185];
bool cmp(stu a,stu b)                        //從頂往下判斷所以從小往大排序 
{
    if(a.l != b.l)
        return a.l < b.l;
    else
        return a.w < b.w;
}
int main()
{
    int k=1;
    int dp[185];                            //dp[i]表示從頂開始到第i個木塊的高度 
    int n,a,b,c,max0,num;
    while(scanf("%d",&n) && n)
    {
        int i,j;
        num=0;
        for(i = 1 ; i <= n ; i++)
        {
            scanf("%d %d %d",&a,&b,&c);
            st[num].l=a,st[num].w=b,st[num++].h=c;        //每個木塊有三种放法 
            st[num].l=a,st[num].w=c,st[num++].h=b;
            st[num].l=b,st[num].w=a,st[num++].h=c;
            st[num].l=b,st[num].w=c,st[num++].h=a;
            st[num].l=c,st[num].w=a,st[num++].h=b;
            st[num].l=c,st[num].w=b,st[num++].h=a;
        }
        sort(st,st+num,cmp);
        for(i = 0 ; i < num ; i++)
        {
            dp[i]=st[i].h;
        }
        for(i = 0 ; i < num ; i++)
        {
            for(j = 0 ; j < i ; j++)
            {
                if(st[j].l < st[i].l && st[j].w < st[i].w && dp[j]+st[i].h > dp[i])            
                {
                    dp[i]=dp[j]+st[i].h;
                }
            }
        }
        sort(dp,dp+num);
        printf("Case %d: maximum height = ",k++);
        printf("%d\n",dp[num-1]);
    }
    return 0;
}

C++版本四

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=190;
struct info
{
    int x;
    int y;
    int z;
    bool operator<(const info &t)const
    {
        if(x!=t.x)
            return x<t.x;
        return y<t.y;
    }
    info(int xx,int yy,int zz):x(xx),y(yy),z(zz){}
    info(){}
};
vector<info>arr;
int dp[N];
int main(void)
{
    int n,i,j,x,y,z;
    int q=1;
    while (~scanf("%d",&n)&&n)
    {
        CLR(dp,0);
        arr.clear();
        for (i=0; i<n; ++i)
        {
            scanf("%d%d%d",&x,&y,&z);
            arr.push_back(info(x,y,z));
            arr.push_back(info(x,z,y));
 
            arr.push_back(info(y,x,z));
            arr.push_back(info(y,z,x));
 
            arr.push_back(info(z,x,y));
            arr.push_back(info(z,y,x));
        }
        sort(arr.begin(),arr.end());
        int SZ=arr.size();
        for (i=0; i<SZ; ++i)
        {
            int pre_max=0;
            for (j=0; j<i; ++j)
            {
                if(arr[j].x<arr[i].x&&arr[j].y<arr[i].y&&dp[j]>pre_max)
                    pre_max=dp[j];
            }
            dp[i]=pre_max+arr[i].z;
        }
        printf("Case %d: maximum height = %d\n",q++,*max_element(dp,dp+SZ));//n^2演算法這裡就要取max,之前搞混了直接輸出最後一個導致WA
    }
    return 0;
}