题意:给你一个凸包,求圆的最小半径使得面积的并>R。
思路:二分这个半径,然后就是纯几何模板了,不知道为什么long double 就能过,double就会WA。反正UVa经常会出现神奇的现象,我表示已经习惯了。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
struct Point
{
long double x,y;
Point(long double x=0,long double y=0):x(x),y(y){}
};
typedef Point Vector;
long double PI=acos(-1.0),eps=1e-10;
Vector operator + (Point A,Point B){return Point(A.x+B.x,A.y+B.y);}
Vector operator - (Point A,Point B){return Point(A.x-B.x,A.y-B.y);}
Point operator * (Point A,long double p){return Point(A.x*p,A.y*p);}
int dcmp(double x){return (x>eps)-(x<-eps);}
bool operator == (const Point &A,const Point &B){return dcmp(A.x-B.x)==0 && dcmp(A.y-B.y)==0;}
long double Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;}
long double Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}
long double Length(Vector A){return sqrt(Dot(A,A));}
long double Angle(Vector A,Vector B){return acos(Dot(A,B)/Length(A)/Length(B));}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
long double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
long double DistanceToLine(Point P,Point A,Point B)
{
Vector v1=B-A,v2=P-A;
return fabs(Cross(v1,v2)/Length(v1));
}
Point GetLineProjection(Point P,Point A,Point B)
{
Vector v=B-A;
return A+v*(Dot(v,P-A)/Dot(v,v));
}
bool OnSegment(Point P,Point A,Point B){return dcmp(Cross(A-P,B-P))==0 && dcmp(Dot(A-P,B-P))<=0;}
Point Zero(0,0);
struct Circle
{
Point c;
double r;
Circle(Point c=Zero,long double r=0):c(c),r(r){}
Point point(long double a){return Point(c.x+r*cos(a),c.y+r*sin(a));}
};
struct Line
{
Point p;
Vector v;
Line(Point p=Zero,Vector v=Vector(0,1)):p(p),v(v){}
Point point(long double t){return Point(p+v*t);}
};
int GetLineCircleIntersection(Line L,Circle C,long double &t1,long double &t2,vector<Point> &sol)
{
long double a=L.v.x;
long double b=L.p.x-C.c.x;
long double c=L.v.y;
long double d=L.p.y-C.c.y;
long double e=a*a+c*c;
long double f=2*(a*b+c*d);
long double g=b*b+d*d-C.r*C.r;
long double delta=f*f-4*e*g;
if(dcmp(delta)<0)
return 0;
if(dcmp(delta)==0)
{
t1=t2=-f/(2*e);
sol.push_back(L.point(t1));
return 1;
}
else
{
t1=(-f-sqrt(delta))/(2*e);
t2=(-f+sqrt(delta))/(2*e);
sol.push_back(L.point(t1));
sol.push_back(L.point(t2));
return 2;
}
}
long double common_area(Circle C,Point A,Point B)
{
if(A==C.c || B==C.c)
return 0;
long double OA=Length(A-C.c),OB=Length(B-C.c);
long double d=DistanceToLine(Zero,A,B);
int sg=dcmp(Cross(A,B));
if(sg==0)
return 0;
long double angle=Angle(A,B);
if(dcmp(OA-C.r)<=0 && dcmp(OB-C.r)<=0)
return Cross(A,B)/2;
if(dcmp(OA-C.r)>=0 && dcmp(OB-C.r)>=0 && dcmp(d-C.r)>=0)
return sg*C.r*C.r*angle/2;
if(dcmp(OA-C.r>=0 && dcmp(OB-C.r)>=0 && dcmp(d-C.r)<0))
{
Point prj=GetLineProjection(Zero,A,B);
if(OnSegment(prj,A,B))
{
vector<Point> p;
Line L=Line(A,B-A);
long double t1,t2;
GetLineCircleIntersection(L,C,t1,t2,p);
long double s1=C.r*C.r*angle/2;
long double s2=C.r*C.r*Angle(p[0],p[1])/2;
s2-=fabs(Cross(p[0],p[1])/2);
s1-=s2;
return sg*s1;
}
else
return sg*C.r*C.r*angle/2;
}
else
{
if(dcmp(OB-C.r)<0)
{
Point temp=A;
A=B;
B=temp;
}
Point inter_point;
long double t1,t2;
Line L=Line(A,B-A);
vector<Point> inter;
GetLineCircleIntersection(L,C,t1,t2,inter);
if(OnSegment(inter[0],A,B))
inter_point=inter[0];
else
inter_point=inter[1];
long double s=fabs(Cross(inter_point,A)/2);
s+=C.r*C.r*Angle(inter_point,B)/2;
return s*sg;
}
}
Point p[60];
int n,t;
long double R;
int main()
{
int i,j,k;
long double l,r,mi,ans;
while(~scanf("%d",&n) && n>0)
{
scanf("%Lf",&R);
for(i=0;i<n;i++)
scanf("%Lf%Lf",&p[i].x,&p[i].y);
p[n]=p[0];
l=0;r=1e10;
while(r-l>1e-6)
{
mi=(l+r)/2;
Circle C(Zero,mi);
ans=0;
for(i=0;i<n;i++)
ans+=common_area(C,p[i],p[i+1]);
if(fabs(ans)>=R)
r=mi;
else
l=mi;
}
printf("Case %d: %.2Lf\n",++t,mi);
}
}