HDU -- Monkey and Banana(ACM Step: 3.2.6)

一、概述

1. 问题描述

有不限数量的n种矩形,每种矩形的长宽高用(x,y,z)表示,矩形可以改变放置的形态,即x,y,z可以两两调换,定义矩形r1可以放置到矩形r2上仅当,r1.x<r2.x且r1.y<r2.y,求这n种矩形可以放置的最大高度。

2. 问题链接

HDU -- Monkey and Banana(ACM Step: 3.2.6)

3. 问题截图

图1.1  问题截图

二、算法思路

1. 约定:

输入的矩形表示为:r_{1},r_{2},...,r_{n}

r_{i}.x,r_{i}.y,r_{i}.z分别表示第i个矩形的长、宽、高

2. 思路

由于每种矩形可以有6中不同的放置方式,每种方式对应的长宽高如下所示:

(x,y,z),(x,z,y)

(y,x,z),(y,z,x)

(z,x,y),(z,y,x)

所以如果输入的矩形数是n,实际上有6n种矩形可以用来构成结果

 

问题的结果可以描述为:

假设a_{1},a_{2},...,a_{m}是得到最大高度的矩形序列,那么问题的结果可以用下述公式表示:

\underset{x_{max} \geqslant a_{i}.x> a_{i+1}.x \geqslant x_{min},\: \:y_{max} \geqslant a_{i}.y>a_{i+1}.y \geqslant y_{min},\: \: a_{i},a_{i+1}\in \left \{ r_{1}, r_{2},..., r_{6n}\right \},\: \: i=1,2,...,m-1}{max} \sum_{k=1}^{m} a_{k}.z

x_{max},x_{min}表示输入矩形中x最大和最小的矩形,将上式中的a_{m}范围单独分析,可以得到等价的下式:

\underset{x_{max} \geqslant a_{i}.x> a_{i+1}.x \geqslant a_{m},x_{max} \geqslant a_{m} \geqslant x_{min},\: \:y_{max} \geqslant a_{i}.y>a_{i+1}.y \geqslant a_{m},\: \: a_{i},a_{i+1}\in \left \{ r_{1}, r_{2},..., r_{6n}\right \},\: \: i=1,2,...,m-1}{max} \sum_{k=1}^{m} a_{k}.z

提出a_{m}的范围,可以得到:

\underset{x_{max} \geqslant a_{m} \geqslant x_{min}}{max}\left ( \underset{x_{max} \geqslant a_{i}.x> a_{i+1}.x \geqslant a_{m},\: \:y_{max} \geqslant a_{i}.y>a_{i+1}.y \geqslant a_{m},\: \: a_{i},a_{i+1}\in \left \{ r_{1}, r_{2},..., r_{6n}\right \},\: \: i=1,2,...,m-1}{max} \sum_{k=1}^{m} a_{k}.z \right )

括号内表示:当a_{m}是解序列的最后一个矩形,即解序列中长、宽最小的矩形,可以得到的高度最大值,可见,括号内实际上是一个关于a_{m}的函数,可以用b[a_{m}]表示,则上述公式可以简化为:

\underset{x_{max} \geqslant a_{m} \geqslant x_{min}}{max}b[a_{m}]

因此题目的解答转变成求解b[a_{m}]数组,并在其中挑出最大值。

现在分析当a_{m}取不同值时,b[a_{m}]之间的关系。

a_{m}=x_{max},此时b[a_{m}]=x_{min}.z,因为当解序列中x(长度)最小的矩形是输入序列中x最大的矩形,此时没有一个矩形可以满足排在它前面的条件,因此这是的b[a_{m}]就是x最大节点的z值。

a_{m}=r_{s}时,r_{s}代表输入序列中x值第二大的矩形,分析此时的b[a_{m}],当x第二大的矩形作为解序列的最后一个矩形时,它能得到的最大值是什么呢?可以发现,首先需要找到满足长宽均大于r_{s}的矩形,此时只有x_{max}矩形可能满足,可能的意思是x_{max}只是x大于r_{s},还需要比较他们的y值。如果都满足,那么此时b[r_{s}]=b[x_{max}]+r_{s}.z表示r_{s}可以放到x_{max}前面;不满足则b[r_{s}]=r_{s}.z

通过分析发现,对于某一个矩形,需要在所有长度大于它的矩形中,通过判断x,y条件,找到最大值,所以可以先将输入矩形序列以长度(x)做递减排列,这样b[a_{m}]的构造就可以利用之前求出的值。

三、算法实现

#include <iostream>    //for cin, cout, endl
#include <algorithm>    //for sort

using std::cin;
using std::cout;
using std::endl;
using std::sort;

//hold the input data
struct Data
{
    int x;
    int y;
    int z;
};

const int MAXSIZE = 30 * 6;    //max of the number of blocks is 30, each block can combination to 6 different kind
Data data[MAXSIZE];
int data_num;    //the number of data elements
long long ans[MAXSIZE];    //ans for answer, hold the result of problem

bool sort_data(Data d1, Data d2)
{
    if(d1.x > d2.x)
        return true;
    else
        return false;
}

//get full permutation of x, y, z where the arr pointing to and put it into data array
void get_permutation(int* arr)
{
    data[data_num].x = arr[0];
    data[data_num].y = arr[1];
    data[data_num].z = arr[2];
    data_num++;

    data[data_num].x = arr[0];
    data[data_num].y = arr[2];
    data[data_num].z = arr[1];
    data_num++;

    data[data_num].x = arr[1];
    data[data_num].y = arr[0];
    data[data_num].z = arr[2];
    data_num++;

    data[data_num].x = arr[1];
    data[data_num].y = arr[2];
    data[data_num].z = arr[0];
    data_num++;

    data[data_num].x = arr[2];
    data[data_num].y = arr[0];
    data[data_num].z = arr[1];
    data_num++;

    data[data_num].x = arr[2];
    data[data_num].y = arr[1];
    data[data_num].z = arr[0];
    data_num++;
}
/*
 * name: calculate
 * description: calculate the result
 * return value: void
 * argument: n indicate the number of blocks from input
 */
long long calculate(int n)
{
    long long ret, tmp;

    sort(data, data+n, sort_data);    //sort the data to an decreasing order of x

    ret = ans[0] = data[0].z;
    for(int i=1; i<n; i++){
        tmp = 0;    //tmp hold the max of previous blocks

        //find the max value of block i(ans[i]) of max value of previous blocks(ans[0~i-1]) that meet the contition of x and y
        for(int j=0; j<i; j++){
            //only meet the x, y condition, the block i can build on the max value of block j
            if(data[j].x>data[i].x && data[j].y>data[i].y && ans[j]>tmp)
                tmp = ans[j];
        }
        ans[i] = data[i].z + tmp;
        if(ans[i] > ret)
            ret = ans[i];    //update the return value
    }
    return ret;
}

//print the result
void print(long long n)
{
    static int num = 0;
    num++;

    cout << "Case " << num << ": maximum height = " << n << endl;
}
int main()
{
    int n;
    int tmp[3];    //hold x, y, z
    long long res;    //res for result, store the return value of function:calculate()

    while(cin>>n && n!=0){
        data_num = 0;

        for(int i=0; i<n; i++){
            for(int j=0; j<3; j++)
                cin >> tmp[j];

            get_permutation(tmp);
        }

        res = calculate(data_num);

        print(res);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值