【HDU-1969】Pie

176 阅读3分钟

题目(浮点二分)

我有N个不同口味、不同大小的派。 有F个朋友会来参加我的派对,每个人会拿到一块派(不能由几个派的小块拼成;可以是一整个派)。 所有人拿到的派必须是同样大小的(但不需要是同样形状的)。 当然,我也要给自己留一块,而这一块也要和其他人的同样大小。 每个派都是一个高为1,半径不等的圆柱体。 请问我们每个人拿到的派最大是多少?


Input

第一行输入一个T代表组数。 随后T组包含两个正整数N和F,1 ≤ N, F ≤ 10000和N个1到10000之间的整数,表示派的数量,朋友的数量和每个派的半径。


Output

输出每个人能得到的最大的派的体积,精确到小数点后四位。




样例

样例输入
3
3 3
4 3 3
1 24
5
10 5
1 4 2 3 4 5 6 5 4 2



样例输出
25.1327
3.1416
50.2655



AC代码

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;
double cake[10001];
int T, N, F;
double PI = acos(-1.0); // 可以获得更精确的值

void erfen(double sum)
{
    double low, mid, high; // 如果用float,得不出结果   注意:这三个值代表的是半径的平方值(也可以理解为面积),而非半径

    /*
    设定二分查找的上限,即用所有饼的总面积(先不乘PI,影响精度)除以人数,说明每个人能分到的最大面积也就是这些(其实根本不可能这么大)
    另一种设定最大值的方法是取所有饼的最大半径。但我认为不好,因为与其说每个人分到的饼和半径有关,还不如说和半径的平方有关。
    */
    high = sum / (F * 1.0);
    low = 0;

    while (high - low > 1e-8) // 如果单纯的用 if(high>low)  也得不出结果。 因为精度的要求很高
    {
        mid = (high + low) / 2.0;
        int servings = 0;
        /*
        二分的思想在于此:
        依次分析每一张饼,看看以mid*PI为面积时,所有的饼可以分成几份(相同大小)。
        如果份数大于人数,则这个mid*PI是可以的,那么再试试可不可以再把单位面积大一点点?(如果不行再慢慢往回缩);
        如果小于人数,说明每个人没办法分到那么多,那么再把单位面积mid*PI减小一点看看能不能满足,即high=mid
        */

        for (int i = 0; i < N; i++)
        {
            servings += (int)(cake[i] / mid); // 更易于理解的写法是(cake[i]*PI)/(mid*PI).表示在当前设定的单位面积下,每张饼可以分成几份,即这张饼可以分给几个人
        }
        if (F > servings)
            high = mid; // 当前方案下所有的饼可以分成的等大份数 小于 人数   。说明单位面积需要缩小一下
        else
            low = mid; //当前方案下所有的饼可以分成的等大份数 大于 人数   。说明单位面积还有进一步增大的空间
    }
    printf("%.4lf\n", low * PI); // low只代表半径的平方。还要再乘以PI
}

int main()
{
    cin >> T;
    while (T--)
    {
        double sum = 0;
        cin >> N >> F;
        for (int i = 0; i < N; i++)
        {
            cin >> cake[i];
            cake[i] = cake[i] * cake[i]; //因为蛋糕的面积与半径成正比,所以可以直接把平方写在数组里
            sum += cake[i];
        }
        F++;

        erfen(sum);
    }
}



题源:acm.hdu.edu.cn/showproblem…