poj 1434 --Fill the Cisterns!(计算几何,二分)

来源:互联网 发布:网易云网络连接失败 编辑:程序博客网 时间:2024/05/01 21:48

http://poj.org/problem?id=1434


Fill the Cisterns!
Time Limit: 5000MS Memory Limit: 10000KTotal Submissions: 1806 Accepted: 653

Description

During the next century certain regions on earth will experience severe water shortages. The old town of Uqbar has already started to prepare itself for the worst. Recently they created a network of pipes connecting the cisterns that distribute water in each neighbourhood, making it easier to fill them at once from a single source of water. But in case of water shortage the cisterns above a certain level will be empty since the water will to the cisterns below.



You have been asked to write a program to compute the level to which cisterns will be lled with a certain volume of water, given the dimensions and position of each cistern. To simplify we will neglect the volume of water in the pipes.


Task

Write a program which for each data set:

reads the description of cisterns and the volume of water,

computes the level to which the cisterns will be filled with the given amount of water,

writes the result.

Input

The first line of the input contains the number of data sets k, 1 <= k <= 30. The data sets follow.

The first line of each data set contains one integer n, the number of cisterns, 1 <= n <= 50 000. Each of the following n lines consists of 4 nonnegative integers, separated by single spaces: b, h, w, d - the base level of the cistern, its height, width and depth in meters, respectively. The integers satisfy 0 <= b <= 10^6 and 1 <= h * w * d <= 40 000. The last line of the data set contains an integer V - the volume of water in cubic meters to be injected into the network. Integer V satisfies 1 <= V <= 2 * 10^9.

Output

The output should consist of exactly d lines, one line for each data set.

Line i, 1 <= i <= d, should contain the level that the water will reach, in meters, rounded up to two fractional digits, or the word 'OVERFLOW', if the volume of water exceeds the total capacity of the cisterns.

Sample Input

320 1 1 12 1 1 11411 7 5 115 6 2 25 8 5 119 4 8 1132411 7 5 115 6 2 25 8 5 119 4 8 178

Sample Output

1.00OVERFLOW17.00



题意:给出N个水池,水池放置的高低不同,容量尺寸也不同,现在给你一定的水量V,求把这些水倒到这些水池后水涨到的高度。

解法:二分。

1.先找出水池的有效区间,即放在最下面的水池的底部LOW,和水池中顶部最高的高度HIGH,即为将要进行二分的区间。

2.二分区间确定一条线,测试这条线是否刚好能让给的水量V涨到这个高度。

3.即使得到的划分线MID能够符合在这条线以下的水量刚好就是V,它也不一定就是正解。

因为有可能这条线没有划过任何水池的中间部分。如例1,当划的线为1.5时,也能满足这个条件。

所以这种情况下必须把这条线当作HIGH继续二分查找。


另外精度控制必须<0.001,我尝试0.002WA了。


代码:

#include<iostream>#include<cmath>#include<cstdio>using namespace std;#define min(a,b) a<b?a:bstruct cistren{  int b,h,w,d,f;}num[50010];int sum,n;double cal(double &line){  double result=0;  for(int i=0;i<n;i++)    {      if(line>num[i].b){  double t=min(line,num[i].f);  result+=(t-num[i].b)*num[i].w*num[i].d;}    }  return result;}int main(){  int t,i;  scanf("%d",&t);  while(t--)    {      scanf("%d",&n);      int total=0;      double low=99999999,high=0;      for(i=0;i<n;i++){  scanf("%d%d%d%d",&num[i].b,&num[i].h,&num[i].w,&num[i].d);  num[i].f=num[i].b+num[i].h;  total+=num[i].h*num[i].w*num[i].d;  if(num[i].b+num[i].h>high)    high=num[i].b+num[i].h;  if(num[i].b<low)    low=num[i].b;}      scanf("%d",∑);      if(sum>total){  printf("OVERFLOW\n");}      else {  double mid;  while(high-low>0.001)    {      mid=(low+high)/2.0;      double ans=cal(mid);      if(fabs(ans-sum)<=0.001){  for(i=0;i<n;i++)    {      if(mid>num[i].b&&num[i].f>mid)break;    }  if(i<n)  break;  else    high=mid;}      else if(ans>sum)high=mid;      elselow=mid;    }  printf("%.2lf\n",mid);}    }}


原创粉丝点击