[POJ 3122] Pie 二分答案+贪心

来源:互联网 发布:免费的收银软件 编辑:程序博客网 时间:2024/05/20 06:29

题目传送门:【POJ 3122】

题目大意:我和朋友们在生日宴会上分享蛋黄派,我们每个人都需要得到相同大小的派,并且每个人只能从一个完整的派上面切下一定大小的派(可以是完整的一块,也可以是切下来的一小块,不过不能由数个切下来的派拼凑而成)。求符合条件时,我们能得到派的面积的最大值。

输入一共有 T 组数据,每组数据的第一行为一个 N 和 F,代表 N 份派和 F 个朋友 (即:一共有 F+1 个人,包含自己);接下来的一行有 N 个数,代表每个派的半径。
输出则为每组数据对应的最大面积,答案的误差最多在 10^-3 之内。

题目分析:
一道比较入门的二分答案题。
由题,每个人最多能得到一个完整派,并且每个派都是等大的;最少则什么也得不到。因此,我们可以对此进行二分。
取 mid 为每个人能获得的最大面积与最小面积的中间值,如果当前的 mid 能使多于 F 个人得到这么大的派,说明每个人可能还会得到更大面积的派,那么往上查找;否则,当 mid 不能的时候,每个人得不到这么大面积的派,就往下查找。最终,我们就可以确定每个人得到的派面积的大小。可以证明这样做是正确的。

下面附上代码:

/* Author:ArcCCcp MEM:284KB TIME:63MS 未加优化*/#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int MX=10005;const double PI=3.1415926535897932;const double ME=1e-5;        //二分查找的最小范围,小于这个范围的查找就显得没有必要int n,f;double size[MX];             //每个派的大小int main(){    int T;    cin>>T;    while (T--){        memset(size,0,sizeof(size));        cin>>n>>f;        f++;                                       //包括自己        double low=0.0,high=0.0;        for (int i=1;i<=n;i++){            cin>>size[i];            size[i]*=size[i];    //这里我们不选择乘上π的值,而是先保存半径的平方,避免浮点运算精度误差过大            if (high < size[i]) high=size[i];        }        double mid=(high+low)/2.0;        while (high-low > ESP){                    //二分答案            int tot=0;            mid=(high+low)/2.0;            for (int i=1;i<=n;i++){                tot+=(int)(size[i]/mid);            }            if (tot < f) high=mid;            else low=mid;    //如果分到当前大小的派的人达到了f,则说明可能还有分的更大的方法,往上查找;    //如果没有达到f,那么当前面积太大,往下查找;        }        printf("%0.4lf\n",mid*PI);    }    return 0;}
原创粉丝点击