Sweety

Practice makes perfect

导航

Monkey and Banana(DP)

Posted on 2016-05-05 22:06  蓝空  阅读(150)  评论(0编辑  收藏  举报

Monkey and Banana
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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

网上题解:

题目倒是不难!对于动态规划的题,我觉得最重要的就是找出所谓的递归方程吧!

这点最为重要!找到了递归方程,代码实现只是时间问题罢了!

这道题目有一些要点要抓住!

1,下一层的面积要严格大于上一层!我在这里错了几次!所谓严格大于,那就是下一层的长宽都大于下一层的长宽或宽长,等于都不行!

2,这道问题比较像01背包问题!我用的方法是拆分!即将一种block拆成6种!

3.注意这里的最大值不一定是dp[n],需要选一下


做这道题的时候也算是曲折坎坷了,下面细细道来。。

其实之前都没怎么系统的做过关于DP的题目,所以借着之前的一点基础,看了两道DP的题型就开始YY敲代码了。。

我的dp[i]定义是在当前Block底面范围能放下的最高的高度,也就是说当前的这个Block是可以放,也可以不放的,所以我的状态转移方程也就成了dp[i]=max{ d[j...]  , d[k...]+h }

这里的dp[j...]是指与i长宽一样所有的Block上能放下的高度(也就是不放当前Block),dp[k]是能在当前面积上放下的(长宽严格比当前长宽小的)高度(也就是放当前的Block)

但是开始的时候感觉不用旋转6种,只旋转了三种,在之后的判断中处理,但是却错了,原因是从小到大排序后,后面的可能能放在前面上面,如果是三种这样状态就少了,比如

3 5 7

6 4 9

所以不能旋转三种,并且按照长宽排序,如下的代码是错误的。。。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;


struct Rec{
  int l;
  int w;
  int h;
}rec[35*6];

bool cmp(Rec a,Rec b){
  if(a.l!=b.l) return a.l<b.l;
  if(a.w!=b.w) return a.w<b.w;
  return a.h<b.h;  ///£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡
  //return a.l*a.w<b.l*b.w;
}

int dp[35*6];
int main()
{
    int n;
    int xx=1;
    while(~rd(n)&&n)
    {
       int coun=1;
       for(int i=1;i<=n;i++){
        scanf("%d%d%d",&rec[coun].l,&rec[coun].w,&rec[coun].h);
        coun++;
        rec[coun].l=rec[coun-1].l ,rec[coun].w=rec[coun-1].h ,rec[coun].h=rec[coun-1].w;
        coun++;
        rec[coun].l=rec[coun-2].w ,rec[coun].w=rec[coun-2].h ,rec[coun].h=rec[coun-2].l;
        coun++;
      }
       coun--;
       sort(rec+1,rec+coun+1,cmp);
      // for(int i=1;i<=coun;i++)
     //   cout<<rec[i].l<<' '<<rec[i].w<<' '<<rec[i].h<<endl;
       int mmax=-INF;
       dp[0]=0;
       for(int i=1;i<=coun;i++){
         int l=rec[i].l,w=rec[i].w,h=rec[i].h ;
         dp[i]=h;
         for(int j=i-1;j>0;j--)
            if( (  rec[j].l<l &&  rec[j].w<w  )|| (rec[j].l<w && rec[j].w<l) )
                dp[i]=max( dp[i] ,h+dp[j]);
                ///!!!!!!!

         int tempMax=-INF;
         for(int j=0;j<i;j++)
            if(rec[j].l==l && rec[j].w==w)
                tempMax=max(tempMax,dp[j]);
         dp[i]=max( tempMax , dp[i] );
         mmax=max(dp[i],mmax);
       }
     //  for(int i=1;i<=coun;i++)
     //   cout<<dp[i]<<' ';
     //  cout<<endl;
       printf("Case %d: maximum height = %d\n",xx++,mmax);
    }
    return 0;
}



但是可以按照面积排序,因为按照面积排序之后上面所说的这种情况就消除了,前面的一定不能放在后面上,于是代码如下:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;


struct Rec{
  int l;
  int w;
  int h;
}rec[35*6];

bool cmp(Rec a,Rec b){
  return a.l*a.w<b.l*b.w;
}

int dp[35*6];
int main()
{
    int n;
    int xx=1;
    while(~rd(n)&&n)
    {
       int coun=1;
       for(int i=1;i<=n;i++){
        scanf("%d%d%d",&rec[coun].l,&rec[coun].w,&rec[coun].h);
        coun++;
        rec[coun].l=rec[coun-1].l ,rec[coun].w=rec[coun-1].h ,rec[coun].h=rec[coun-1].w;
        coun++;
        rec[coun].l=rec[coun-2].w ,rec[coun].w=rec[coun-2].h ,rec[coun].h=rec[coun-2].l;
        coun++;
      }
       coun--;
       sort(rec+1,rec+coun+1,cmp);
      // for(int i=1;i<=coun;i++)
     //   cout<<rec[i].l<<' '<<rec[i].w<<' '<<rec[i].h<<endl;
       int mmax=-INF;
       dp[0]=0;
       for(int i=1;i<=coun;i++){
         int l=rec[i].l,w=rec[i].w,h=rec[i].h ;
         dp[i]=h;
         for(int j=i-1;j>0;j--)
            if( (  rec[j].l<l &&  rec[j].w<w  )|| (rec[j].l<w && rec[j].w<l) )
                dp[i]=max( dp[i] ,h+dp[j]);
                ///!!!!!!!

         int tempMax=-INF;
         for(int j=0;j<i;j++)
            if(rec[j].l==l && rec[j].w==w)
                tempMax=max(tempMax,dp[j]);
         dp[i]=max( tempMax , dp[i] );
         mmax=max(dp[i],mmax);
       }
     //  for(int i=1;i<=coun;i++)
     //   cout<<dp[i]<<' ';
     //  cout<<endl;
       printf("Case %d: maximum height = %d\n",xx++,mmax);
    }
    return 0;
}

旋转六种的直接用上面的思路就完全可以了。。代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;


struct Rec{
  int l;
  int w;
  int h;
}rec[35*6];

bool cmp(Rec a,Rec b){
  if(a.l!=b.l) return a.l<b.l;
  if(a.w!=b.w) return a.w<b.w;
  return a.h<b.h;  ///£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡
}

int dp[35*6];
int main()
{
    int n;
    int xx=1;
    while(~rd(n)&&n)
    {
       int coun=1;
       for(int i=1;i<=n;i++){
        scanf("%d%d%d",&rec[coun].l,&rec[coun].w,&rec[coun].h);
        coun++;  ///×¢Ò⣡£¡£¡
        rec[coun].l=rec[coun-1].l ,rec[coun].w=rec[coun-1].h ,rec[coun].h=rec[coun-1].w;
        coun++;
        rec[coun].l=rec[coun-2].w ,rec[coun].w=rec[coun-2].h ,rec[coun].h=rec[coun-2].l;
        coun++;

        rec[coun].l=rec[coun-3].w ,rec[coun].w=rec[coun-3].l ,rec[coun].h=rec[coun-3].h;
        coun++;
        rec[coun].l=rec[coun-4].h ,rec[coun].w=rec[coun-4].l ,rec[coun].h=rec[coun-4].w;
        coun++;
        rec[coun].l=rec[coun-5].h ,rec[coun].w=rec[coun-5].w ,rec[coun].h=rec[coun-5].l;
        coun++;
      }
       coun--;
       sort(rec+1,rec+coun+1,cmp);
       int mmax=-INF;
       dp[0]=0;
       for(int i=1;i<=coun;i++){
         int l=rec[i].l,w=rec[i].w,h=rec[i].h ;
         dp[i]=h;
         for(int j=i-1;j>0;j--)
            if( (  rec[j].l<l &&  rec[j].w<w  ) )
                dp[i]=max( dp[i] ,h+dp[j]);
                ///!!!!!!!

         int tempMax=-INF;
         for(int j=0;j<i;j++)
            if(rec[j].l==l && rec[j].w==w)
                tempMax=max(tempMax,dp[j]);
         dp[i]=max( tempMax , dp[i] );
         mmax=max(dp[i],mmax);
       }

       printf("Case %d: maximum height = %d\n",xx++,mmax);
    }
    return 0;
}

其实网上盛传的比较多的一种版本是下面的这种,这里的dp[i]指的是放在当前Block上的最大高度,和上面的一种区别是当前的这个Block一定是放在最下面的。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define MAX 100005
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
///map<int,int>mmap;
///map<int,int >::iterator it;
using namespace std;


struct Rec{
  int l;
  int w;
  int h;
}rec[35*6];

bool cmp(Rec a,Rec b){
  if(a.l!=b.l) return a.l<b.l;
  if(a.w!=b.w) return a.w<b.w;
  return a.h<b.h;  ///£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£¡
}

int dp[35*6];
int main()
{
    int n;
    int xx=1;
    while(~rd(n)&&n)
    {
       int coun=1;
       for(int i=1;i<=n;i++){
        scanf("%d%d%d",&rec[coun].l,&rec[coun].w,&rec[coun].h);
        coun++;  ///×¢Ò⣡£¡£¡
        rec[coun].l=rec[coun-1].l ,rec[coun].w=rec[coun-1].h ,rec[coun].h=rec[coun-1].w;
        coun++;
        rec[coun].l=rec[coun-2].w ,rec[coun].w=rec[coun-2].h ,rec[coun].h=rec[coun-2].l;
        coun++;

        rec[coun].l=rec[coun-3].w ,rec[coun].w=rec[coun-3].l ,rec[coun].h=rec[coun-3].h;
        coun++;
        rec[coun].l=rec[coun-4].h ,rec[coun].w=rec[coun-4].l ,rec[coun].h=rec[coun-4].w;
        coun++;
        rec[coun].l=rec[coun-5].h ,rec[coun].w=rec[coun-5].w ,rec[coun].h=rec[coun-5].l;
        coun++;
      }
       coun--;
       sort(rec+1,rec+coun+1,cmp);

       int mmax=-INF;
       for(int i=1;i<=coun;i++){
         int l=rec[i].l,w=rec[i].w,h=rec[i].h ;
         dp[i]=h;
         for(int j=i-1;j>0;j--)
            if( rec[j].l<l  &&  rec[j].w<w )
                dp[i]= max(dp[i],h+dp[j] );
         if(mmax<dp[i])
            mmax=dp[i];
       }
       printf("Case %d: maximum height = %d\n",xx++,mmax);
    }
    return 0;
}