[ZJOI2006]碗的叠放

Description

小H有n个碗需要放进橱柜,她希望将他们叠起来放置。你知道每个碗都是规则的圆柱体,并且都是上宽下窄,你已经测量出了每个碗的两个半径及高,请你帮小H找出一种叠放顺序,使得叠放出来的碗堆的高度尽量小,比如:

20190904132043942.jpg

Input

第一行一个整数n,表示碗的数目。以下n行,每行三个整数h,r1,r2。分别表示碗高及两个半径。

Output

仅一个数,表示最小的高度。答案四舍五入取整。

Sample Input

3
50 30 80
35 25 70
40 10 90

Sample Output

55

HINT

数据范围:100%数据满足n < = 9。所有输入的数绝对值不超过1000。

n<=9,直接想一下暴力枚举每一种放置顺序,求最小的答案即可。

那我们怎么求一种排序方案的高度呢?

分几种情况讨论:

最简单的两种:

1.如果上面的碗的碗底半径比下面的碗的碗口半径还要大(或者等于),直接卡住。

2.如果上面的碗的碗口半径比下面的碗的碗口半径还要小(或等于),可以放进去,但有可能在下底面卡住。

如果这两种情况都不是,那只能看一下碗壁的斜率了。

1.下面的碗壁大于上面的碗壁的斜率

算出在哪里是卡住的,再加上即可。

2.下面的碗壁小于等于上面的碗壁的斜率

同理。

但是有一个小情况:有可能放完碗后中间是凹下去的,这时要取得是外面的碗高。

#include<bits/stdc++.h>
using namespace std;
struct data
{
    double a,b,c,d;
}a[21],b[21];
int n,c[21];
double x,y,z;
data putin(double a,double b,double c,double d)
{
    data aa;
    aa.a=a;
    aa.b=b;
    aa.c=c;
    aa.d=d;
    return aa;
}
double getxl(data a)
{
    return (a.d-a.b)/(a.c-a.a);
}
double work(data a,data b)//两个碗放置的高度 
{
    double p=a.b;
    if(b.a>=a.c)
    {
        return a.d;
    }
    a.b=0;
    a.d-=p;
    if(getxl(a)>getxl(b))
    {
        if(b.c>=a.c)
        {
            double k=a.d-(a.c-b.a)*getxl(b);
            return p+max(k,0.0);
        }
        double k=a.d-b.d-(a.c-b.c)*getxl(a);
        return p+max(k,0.0);
    }else{
        if(a.a>b.a)
        {
            return p;
        }
        double k=a.d-(a.c-b.a)*getxl(a);
        return p+max(k,0.0);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf%lf",&x,&y,&z);
        a[i]=putin(y,0.0,z,x);
    }
    for(int i=1;i<=n;i++)
    {
        c[i]=i;
    }
    double minn=1e9;
    while(1)//计算每种排列的总高度 
    {
        b[0]=putin(1e9,0.0,1e9,0.0);
        for(int i=1;i<=n;i++)
        {
            double maxn=0;
            for(int j=0;j<i;j++)
            {
                maxn=max(maxn,work(b[j],a[c[i]]));
            }
            b[i]=putin(a[c[i]].a,a[c[i]].b+maxn,a[c[i]].c,a[c[i]].d+maxn);//放好的碗 
        }
        double maxn=0;
        for(int i=1;i<=n;i++)
        {
            maxn=max(maxn,b[i].d);
        }
        minn=min(minn,maxn);
        if(!next_permutation(c+1,c+n+1))//下一种排列 
        {
            break;
        } 
    }
    printf("%.0lf\n",minn);
    return 0;
} 

转载于:https://www.cnblogs.com/2017gdgzoi44/p/11458590.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值