POJ-3122 Pie 分蛋糕(二分法)
My birthday is coming up and traditionally I’m serving pie. Not just one pie, no, I have a number N of them, of various tastes and of various sizes. F of my friends are coming to my party and each of them gets a piece of pie. This should be one piece of one pie, not several small pieces since that looks messy. This piece can be one whole pie though.
My friends are very annoying and if one of them gets a bigger piece than the others, they start complaining. Therefore all of them should get equally sized (but not necessarily equally shaped) pieces, even if this leads to some pie getting spoiled (which is better than spoiling the party). Of course, I want a piece of pie for myself too, and that piece should also be of the same size.
What is the largest possible piece size all of us can get? All the pies are cylindrical in shape and they all have the same height 1, but the radii of the pies can be different.
Input
One line with a positive integer: the number of test cases. Then for each test case:
One line with two integers N and F with 1 ≤ N, F ≤ 10 000: the number of pies and the number of friends.
One line with N integers ri with 1 ≤ ri ≤ 10 000: the radii of the pies.
Output
For each test case, output one line with the largest possible volume V such that me and my friends can all get a pie piece of size V. The answer should be given as a floating point number with an absolute error of at most 10 −3.
Sample Input
3
3 3
4 3 3
1 24
5
10 5
1 4 2 3 4 5 6 5 4 2
Sample Output
25.1327
3.1416
50.2655
这是一道二分题,题目的大意是这样的:
给出T组数据,每组数据给出N个蛋糕(大小不一),现在要把这些蛋糕平均分给x个来参加party的朋友,当然还要留自己的一份(即平分为x+1块)(蛋糕高度均为一,可以简化为划分同样大小的面积问题(只考虑二维空间,不必考虑其三维空间))
一开始的思路是这样的:
把最大的蛋糕面积先标记下来,然后从0到该最大面积之间挑选所能取到的面积,一直对其进行二分下去得到结果
(二分时每次使所有蛋糕对挑选的蛋糕面积做处理: sum=floor(sum+a[i]/m);得到划分该蛋糕的面积所能划分的份数,最后return sum>=(y+1);使所有人都能得到蛋糕)
但是这种方法多次调用函数且函数内每次都要进行x次循环,最后这种方法超时(WA)了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double PI = 3.1415926;
int x,y;
double a[10001];
double Max(double x,double y)
{
if(x>=y)
return x;
else return y;
}
double mid(double m)
{
int sum=0;
for(int i=1;i<=x;i++)
{
sum=floor(sum+a[i]/m);
}
return sum>=(y+1);
}
int main()
{
int n;
cin>>n;
while(n--)
{
cin>>x>>y;
double max=-1;
for(int i=1;i<=x;i++)
{
cin>>a[i];
a[i]=a[i]*a[i]*PI;
max=Max(max,a[i]);
}
double l=0,r=max;
while(r-l>1e-4)
{
double m=(l+r)/2;
if (mid(m)) l=m;
else r=m;
}
printf("%.4lf\n",l);
}
return 0;
}
后来做了很多简化不超时了,下面是稍微简化一些的:(输入输出方面等)(这里表示圆周率的方式可以使用 acos(-1.0))(max没有简化,使用了一个很大的数,默认存在大蛋糕(反正最后要符合条件,这里都可以)但是不用循环一直查找max值了)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define pi acos(-1.0)
double r[10001];
double s[10001];
int n,len;
double cha(double mid)
{
int sum=0;
for(int i=0;i<n;i++)
{
sum=sum+(int)(s[i]/mid);
}
return sum;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&len);len++;
for( int i=0;i<n;i++)
{
scanf("%lf",&r[i]);
s[i]=pi*r[i]*r[i];
}
double l=0.0,r=1000000000.0;
int s=100;
double ans;
while(s--)
{
double mid=(l+r)/2.0;
if(cha(mid)>=len)
{
ans=mid;
l=mid;
}
else
{
r=mid;
}
}
printf("%.4lf\n",ans);
}
return 0;
}