先上题目:
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
题目大意:F+1个人(F个朋友和ta自己)分N张圆柱形的派,每人一小块,大小相等。每张派高度为1,半径为ri。
将每张派分成体积为x(x>=1,double类型)的F+1块。每张派可以有残留但不能使用多张派的残留凑成一小块。即一个体积为5的派切出来了体积为4的一小块,剩余体积为1的不够再切一个4,直接丢弃(滑稽)。
求x,误差须在0.001范围内。
思路:
求一个误差在0.001范围内的答案,暴力枚举死亡(滑稽) 那怎么求出符合条件的可以将全部派分为F+1小块的数呢?首先可以确定答案肯定在Xmin(体积最小派的体积)和Xmax(体积最大派的体积)之间,那么我们可以使用效率较高的二分查找解题简直废话 。
实现二分法查找:
首先,假设查找表中的元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
————————引自百度百科词条“二分查找”
本题几个可以留意的点:
<1. 读入半径保存体积,用体积去查找,以便减小误差(误差极为重要)否则用半径查容易wa = = 。
<2. 二分查找时上下边界的合理判断可以减少时间,上边界笔者定为每张派都无剩余时下每人分到一小块的大小,下边界为确保每个人都有派时最大的大小(有点绕口)。
❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ 我是分割线 ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️ ❤️
注释版代码
//#include
#include
#include
#define PI acos(-1.0)//PI为圆周率;
using namespace std;
int n,friendsnum;
double a[10010],maxsize,cul;
double binary_search();
int judge(double size);
//主函数;
int main(){
int t;
scanf("%d",&t);//多实例;
while(t--)
{
maxsize=0;cul=0;//maxsize为最大的派体积,cul为派总体积,记得初始化;
scanf("%d%d",&n,&friendsnum);
friendsnum++;
int temp;
for(int i=0;i<n;i++)
{
scanf("%d",&temp);//读入半径;
a[i]=(temp*temp*PI);//计算体积;
cul+=a[i];//累加总体积;
if(maxsize<a[i]) maxsize=a[i];//比较最大值;
}
double answer=binary_search();//查找;
printf("%.4f\n",answer);
}
return 0;
}
//在(maxsize/friendsnum,cul/friendsnum)的有理数区间内进行二分查找;
double binary_search(){
double high=cul/friendsnum,low=maxsize/friendsnum;
//上边界为每张派都无剩余的情况下每人分到的大小,下边界为确保每个人都有派时最大的大小;
double size=(high+low)/2;
while(high-low>0.0000001)//趋近于目标值时跳出;
{
if(judge(size)) low=size;//确定够分,求最大值,改变下边界;
else high=size;//如果每一小块过大,改变上边界;
size=(high+low)/2;
}
return size;
}
//判断是否够F+1个人分,即查找条件;
int judge(double size){
int sum=0;//每小块大小为size时的总块数;
for(int i=0;i<n;i++)
{
sum+=(int)(a[i]/size);//块当然是整块(int);
if(sum>=friendsnum) return 1;//够分时果断return 1;
}
return 0;//循环结束还不够分就只能return 0;
}
简洁版代码
#include
#include
#define PI acos(-1.0)
using namespace std;
int n,friendsnum;
double a[10010],maxsize,cul;
int judge(double size){
int sum=0;
for(int i=0;i<n;i++)
{
sum+=(int)(a[i]/size);
if(sum>=friendsnum) return 1;
}
return 0;
}
double binary_search(){
double high=cul/friendsnum,low=maxsize/friendsnum;
double size=(high+low)/2;
while(high-low>0.0000001)
{
if(judge(size)) low=size;
else high=size;
size=(high+low)/2;
}
return size;
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
maxsize=0;cul=0;
scanf("%d%d",&n,&friendsnum);
friendsnum++;
int temp;
for(int i=0;i<n;i++)
{
scanf("%d",&temp);
a[i]=(temp*temp*PI);
cul+=a[i];
if(maxsize<a[i]) maxsize=a[i];
}
double answer=binary_search();
printf("%.4f\n",answer);
}
return 0;
}
祝每个看过这篇题解的大佬们都能ac!