poj 1434

题目概述

水箱系统中有N个长方体水箱,每个水箱底面长w,宽d,水箱高h,水箱下底面距离地面的高度b,所有水箱在下底面由水管互相连通,水管中水量不计,现将V体积水倒入整个系统,问水是否会溢出,如果不会溢出,求水面距离地面的高度

时限

5000ms/15000ms

输入

第一行正整数times,其后有times组数据,每组数据第一行正整数N,其后N行,每行4个整数b,h,w,d,下一行正整数V

限制

1<=times<=30;1<=N<=50000;0<=b<=1e6;1<=h*w*d<=40000;1<=V<=2e9

输出

每组数据在一行中输出,若会溢出,输出OVERFLOW,否则输出一个保留两位小数的浮点数,为所求水面高度

样例输入

3
2
0 1 1 1
2 1 1 1
1
4
11 7 5 1
15 6 2 2
5 8 5 1
19 4 8 1
132
4
11 7 5 1
15 6 2 2
5 8 5 1
19 4 8 1
78

样例输出

1.00
OVERFLOW
17.00

讨论

二分,是的,这和计算几何没半毛钱关系,矩形面积并做多的额差点开线段树,主要的思想,首先判断注水量是否超过系统上限,然后二分水面高度,直到到达精度为止
实现方面,不难发现底面长宽除了算出底面积外没有其他用,算完就扔掉行了,另外读入时顺手算出单个水箱体积以及系统体积,以便判断是否溢出,二分的下界是0,上界不知为何需要开到非常大(1e9)才能过,二分过程中,需要注意算得每个水箱装入的水量不能超过水箱体积,否则结果必然会出错
实际上也可以对水箱按离地高度升序排序以尽快完成每一趟二分,不过似乎对速度没什么提升,也就去掉那部分

题解状态

960K,766MS,C++,1015B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 50002
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-8

struct It//item 水箱的结构
{
    int b, h, S, V;//b 离地高度 h 水箱内高 这两个变量名是题目给的 S 水箱底面积 V 水箱体积
}its[MAXN];
int N, V;//水箱总数 注水量
void fun()
{
    int sumV = 0;//系统可容纳水量上限
    for (int p = 0; p < N; p++) {
        int w, d;//底面长宽 没有其他用途 不用存到结构体中
        scanf("%d%d%d%d", &its[p].b, &its[p].h, &w, &d);//input
        its[p].S = w*d, sumV += its[p].V = its[p].S*its[p].h;//算出底面积 体积 并加入系统容纳量
    }
    scanf("%d", &V);//input
    if (V > sumV) {//系统装不开的情况
        printf("OVERFLOW\n");//output
        return;
    }
    double low = 0, high = 2e9, mid;
    while (high - low > 4e-3) {//题目要求精度1e-2 取4e-3在避免舍入误差前提下尽量减少二分次数
        mid = (high + low) / 2;//二分的是水面高度
        double sum = 0;//在当前水面高度下系统装水量
        for (int p = 0; p < N; p++) {
            if (mid > its[p].b) {
                double v = (mid - its[p].b)*its[p].S;
                sum += v > its[p].V ? its[p].V : v;//当算出要装入单个水箱的水量超过水箱体积时 多出的部分不能计入
            }
        }
        if (sum >= V)
            high = mid;
        else
            low = mid;
    }
    printf("%.2lf\n", mid);
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", &times);//input
    while (times--) {
        scanf("%d", &N);//output
        fun();
    }
}

EOF

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值