题面:【POJ3122】Pie
按理来说,这题应该是一道很水的二分题,可是精度问题却折磨了我很久很久,经过无数次的修改,我总算A了这一题。
你可以二分最终每个人所能得到的Pie的大小,而验证函数check()其实也非常简单:
bool check(double x)//验证函数 { int t=0;//记录当Pie的大小为x时所能得到的Pie的数量 for(int i=1;i<=n;i++) t+=floor(s[i]/x);//统计Pie的数量,s[]数组表示每个Pie的大小 return t>=m;//若所能得到的Pie的数量比人数多(初始化时记得将m加1,因为自己也需要一份,这是一个坑),就返回true,否则为false }有了check()函数,就可以轻易地打出二分函数了:
void find(double l,double r)//二分函数 { if(abs(l-r)<ff) return;//当l与r之间的差距比ff(1e-6)还小,就退出函数 double mid=(l+r)/2;//计算l与r的中间值 if(check(mid)) ans=mid,find(mid+ff,r);//若Pie的大小为mid可以实现,就将mid作为答案,并尝试得到更大的答案 else find(l,mid-ff);//若Pie的大小为mid无法实现,就向更小的区域去寻找答案 }
这样一来,整个程序就出来了:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #define max(x,y) (x>y?x:y) #define min(x,y) (x<y?x:y) #define ff 0.000001//一个特别小的数(1e-6) #define N 10000 using namespace std; const double pi=4*atan(1.0);//将π的值作为一个常数 int n,m,a[N+5];//n存储Pie的数量,m存储人数,a[]存储每个Pie的半径 double ans,s[N+5];//ans存储答案,s[]存储每个Pie的面积 int read()//读优 { int x=0,f=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') f=-1,ch=getchar(); while(ch>='0'&&ch<='9') (x*=10)+=ch-'0',ch=getchar(); return x*=f; } void write(int x)//输优 { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } bool check(double x)//验证函数(详解见上) { int t=0; for(int i=1;i<=n;i++) t+=floor(s[i]/x); return t>=m; } void find(double l,double r)//二分函数(详解见上) { if(abs(l-r)<ff) return; double mid=(l+r)/2; if(check(mid)) ans=mid,find(mid+ff,r); else find(l,mid-ff); } int main() { int T=read();//一共有T组数据 while(T--) { n=read(),(m=read())++;//将m加1,因为自己也需要一份,这是一个坑 double Max=0;//存储上界 for(int i=1;i<=n;i++) a[i]=read(),s[i]=a[i]*a[i]*pi,Max=max(Max,s[i]);//读入Pie的半径,计算出Pie的面积,并更新上界 ans=0;//答案初始化为0 find(ff,Max);//进行二分答案 printf("%.4f\n",ans);//输出(题目要求保留4位小数) } return 0; }
版权声明:转载请注明地址