杭电 3756 Dome of Circus 解题报告
将所有的点转化为x-z平面上,求使所有的点在直线x/r+z/h=1的下方,且使r*r*h最小的h与r的值。
依然使用三分法。可以这么多点,如何处理呢?
笔者首先选取x坐标最大的点,使直线过此点,逆时针旋转至下一个点,三分求体积最小值。再使以下一点逆时针旋转,直至没有点或者直线斜率k>=0。这样每次所有的点都在直线下方。AC代码如下:
#include<iostream> #include<cmath> using namespace std; double pi=acos(-1.0); double eps=1e-9; double fun(double x,double y,double q) { double r,h; r=x+y*tan(q*pi); h=x/tan(q*pi)+y; return r*r*h; } double threeSplit(double x,double y,double a,double b) { double mida,midb; while(b-a>eps) { mida=(a+a+b)/3; midb=(a+b+b)/3; if(fun(x,y,mida)<fun(x,y,midb)) b=midb; else a=mida; } return a; } struct Point { double x,y; } p[10001]; int main() { int cas,i,n,max_p,current_p,next_p; double q,max_q,v,max_v,k,max_k,max_x,a,b; cin>>cas; while(cas--) { cin>>n; max_x=-1; current_p=0; for(i=1;i<=n;i++) { cin>>a>>b>>p[i].y; p[i].x=sqrt(a*a+b*b); if(max_x<p[i].x) { max_x=p[i].x; current_p=i; } else if(max_x==p[i].x && p[i].y>p[current_p].y) current_p=i; } max_v=a=b=eps; while(1) { next_p=-1; max_k=0; for(i=1;i<=n;i++) if(i!=current_p) if(p[i].y-p[current_p].y>0 && max_k<(k=(p[i].y-p[current_p].y)/(p[current_p].x-p[i].x))) { max_k=k; next_p=i; } if(next_p==-1||max_k<=0) b=0.5-eps; else b=atan(1/max_k)/pi; q=threeSplit(p[current_p].x,p[current_p].y,a,b); if(max_v<(v=fun(p[current_p].x,p[current_p].y,q))) { max_v=v; max_q=q; max_p=current_p; } if(next_p==-1||max_k<=0) break; current_p=next_p; a=b; } printf("%.3f %.3f\n",p[max_p].x/tan(max_q*pi)+p[max_p].y+eps,p[max_p].x+p[max_p].y*tan(max_q*pi)+eps); } }
笔者已经不想改这个代码了。。。希望你可以看懂
网上还搜到一份不一样的代码,思路不太一样,笔者没有认真去看。因为这题也花了不少时间,懒得去弄了。。。