题意:传送门
题解:要求所有点在直线同侧,因此直线不能穿过凸包,选择凸包的边所在的直线,比选择和凸包相离的直线更划算。但是凸包上的边有 n n n条,如果每个点对应都算一次,那么 O ( n 2 ) O(n^2) O(n2)岂不是 T T T,如果能 O ( 1 ) O(1) O(1)算出来,岂不是很好,那么改用解析几何的方式,直线的一般方程式为 A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0,点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)到该直线的距离为 ∣ A x 0 + B y 0 + C ∣ A 2 + B 2 \frac{|Ax_0+By_0+C|}{\sqrt{A^2+B^2}} A2+B2∣Ax0+By0+C∣,所有点都是直线的同一侧,那么所有的 ∣ A x 0 + B y 0 + C ∣ |Ax_0+By_0+C| ∣Ax0+By0+C∣的正负号相同,这样就可以预处理出所有 x x x和 y y y的坐标之和, O ( 1 ) O(1) O(1)时间内算出总距离。
c o d e : code: code:
#include<bits/stdc++.h>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pdd pair<double,double>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define rush() int T;scanf("%d",&T);while(T--)
#define debug(x) cout<<#x<<": "<<x<<endl
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define pf(x) printf("%d\n",x)
#define pf2(x,y) printf("%d %d\n",x,y)
#define pf3(x,y,z) printf("%d %d %d\n",x,y,z)
#define all(x) (x).begin(),(x).end()
#define PI acos(-1.0)
#define E exp(1.0)
#define db double
#define ll long long
#define ld long double
#define ull unsigned long long
//#define io
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
//#define gc getchar
//char buf[1<<21],*p1=buf,*p2=buf;
//inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
//inline int read()
//{
// int ret=0,f=0;char c=gc();
// while(!isdigit(c)){if(c=='-')f=1;c=gc();}
// while(isdigit(c)){ret=ret*10+c-48;c=gc();}
// if(f)return -ret;return ret;
//}
const int N=10000+5;
const db EPS=1e-8;
inline int sign(db a){
return a<-EPS?-1:a>EPS;}
inline int cmp(db a,db b){
return sign(a-b);}
inline db sqr(db x){
return x*x;}
struct Point{
db x,y;
Point(){
}
Point(db _x,db _y):x(_x),y(_y){
}
void input(){
scanf("%lf%lf",&x,&y);}
void output(){
printf("%.10f %.10f\n",x,y);}
bool operator == (Point b)const{
return sign(x-b.x)==0&&sign(y-b.y)==0;
}
bool operator < (Point b)const{
return sign(x-b.x)==0?sign(y-b.y)<0:x<b.x;
}
Point operator + (const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator - (const Point &b)const{
return Point(x-b.x,y-b.y);
}
db operator ^ (const Point &b)const{
return x*b.y-y*b.x;
}
db operator * (const Point &b)const{
return x*b.x+y*b.y;
}
db len(){
return hypot(x,y);}
db len2(){
return x*x+y*y;}
db distance(Point p){
return hypot(x-p.x,y-p.y);}
Point operator * (const db &k)const{
return Point(x*k,y*k);
}
Point operator / (const db &k)const{
return Point(x/k,y/k);
}
db rad(Point a,Point b){
Point p=*this;
return fabs(atan2(fabs((a-p)^(b-p)),(a-p)*(b-p)));
}
Point unit(){
return *this/len();}
Point trunc(db r){
db l=len();
if(!sign(l))return *this;
r/=l;
return Point(x*r,y*r);
}
Point rotleft(){
return Point(-y,x);}
Point rotright(){
return Point(y,-x);}
Point rotate(Point p,db angle){
Point v=(*this)-p;
db c=cos(angle),s=sin(angle);
return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
}
};
#define dot(p1,p2,p3) ((p2.x-p1.x)*(p3.x-p1.x)+(p2.y-p1.y)*(p3.y-p1.y))
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define crossOp(p1,p2,p3) sign(cross(p1,p2,p3))
struct Line{
Point s,e;
Line(){
}
Line(Point _s,Point _e):s(_s),e(_e){
}
bool operator == (Line v){
return (s==v.s)&&(e==v.e);
}
Line(Point p,db angle){
s=p;
if(sign(angle-PI/2)==0)e=(s+Point(0,1));
else e=(s+Point(1,tan(angle)));
}
Line(db a,db b,db c){
if(sign(a)==0){
s=Point(0,-c/b);e=Point(1,-c/b);
}else if(sign(b)==0){
s=Point(-c/a,0);e=Point(-c/a,1);
}else{
s=Point(0,-c/b);e=Point(1,(-c-a)/b);
}
}
void input(){
s.input();e.input();}
void adjust(){
if(e<s)swap(s,e);}
db length(){
return s.distance(e);}
//[0,PI)
db angle(){
db k=atan2(e.y-s.y,e.x-s.x);
if(sign(k)<0)k+=PI;
if(sign(k-PI)==0)k-=PI;
return k;
}
//line1 on the left|2 on the right|3 on line|
int relation(Point p){
int c=sign((p-s)^(e-s));
if(c<0)return 1;
else if(c>0)return 2;
else return 3;
}
bool pointonseg(Point p){
return sign((p-s)^(e-s))==0&&sign((p-s)*(p-e))<=0;
}
bool parallel(Line v){
return sign((e-s)^(v.e-v.s))==0;
}
//|0 not intersect|1 non-standard|2 intersect|
int segcrossseg(Line v){
int d1=sign((e-s)^(v.s-s));
int d2=sign((e-s)^(v.e-s));
int d3=sign((v.e-v.s)^(s-v.s));
int d4=sign((v.e-v.s)^(e-v.s));
if((d1^d2)==-2&&(d3^d4)==-2)return 2;
return (d1==0&&sign((v.s-s)*(v.s-e))<=0)||
(d2==0&&sign((v.e-s)*(v.e-e))<=0)||
(d3==0&&sign((s-v.s)*(s-v.e))<=0)||
(d4==0&&sign((e-v.s)*(e-v.e))<=0);
}
//|0 not intersect|1 non-standard|2 intersect|
int linecrossseg(Line v){
int d1=sign((e-s)^(v.s-s));
int d2=sign((e-s)^(v.e-s));
if((d1^d2)==-2)return 2;
return (d1==0||d2==0);
}
//|0 parallel|1 coincides|2 intersect|
int linecrossline(Line v){
if((*this).parallel(v))return v.relation(s)==3;
return 2;
}
//要保证两直线不平行或重合
Point crosspoint(Line v){
db a1=(v.e-v.s)^(s-v.s);
db a2=(v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
db dispointtoline(Point p){
return fabs((p-s)^(e-s))/length();
}
db dispointtoseg(Point p){
if(sign((p-s)*(e-s))<0||sign((p-e)*(s-e))<0)return min(p.distance(s),p.distance(e));
return dispointtoline(p);
}
//前提是两线段不相交,相交距离就是0了
db dissegtoseg(Line v){
return min(min(dispointtoseg(v.s),dispointtoseg(v.e)),min(v.dispointtoseg(s),v.dispointtoseg(e)));
}
Point lineprog(Point p){
return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()) );
}
Point symmetrypoint(Point p){
Point q = lineprog(p);
return Point(2*q.x-p.x,2*q.y-p.y);
}
};
struct circle{
Point p;
db r;
circle(){
}
circle(Point _p,db _r):p(_p),r(_r){
}
circle(db _x,db _y,db _r){
p=Point(_x,_y);r=_r;
}
Point point(db a){
return Point(p.x+r*cos(a),p.y+r*sin(a));
}
//三角形的外接圆
circle(Point a,Point b,Point c){
Line u=Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
Line v=Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
p=u.crosspoint(v);
r=p.distance(a);
}
//三角形的内切圆
circle(Point a,Point b,Point c,bool t){
Line u,v;
db m=atan2(b.y-a.y,b.x-a.x),n=atan2(c.y-a.y,c.x-a.x);
u.s=a;
u.e=u.s+Point(cos((n+m)/2),sin((n+m)/2));
m=atan2(a.y-b.y,a.x-b.x),n=atan2(c.y-b.y,c.x-b.x);
v.s=b;
v.e=v.s+Point(cos((n+m)/2),sin((n+m)/2));
p=u.crosspoint(v);
r=Line(a,b).dispointtoseg(p);
}
void input(){
p.input();
scanf("%lf",&r);
}
void output(){
printf("%.2f %.2f %.2f\n",p.x,p.y,p,r);
}
bool operator == (circle v){
return (p==v.p)&&sign(r-v.r)==0;
}
bool operator < (circle v)const{
return ((p<v.p)||((p==v.p)&&sign(r-v.r)<0));
}
db area(){
return PI*r*r;}
db circumference(){
return 2*PI*r;}
//|0 not|1 on|2 in|
int relation(Point b){
db dst=b.distance(p);
if(sign(dst-r)<0)return 2;
else if(sign(dst-r)==0)return 1;
return 0;
}
//|0 not|1 on|2 in|
int relationseg(Line v){
db dst=v.dispointtoseg(p);
if(sign(dst-r)<0)return 2;
else if(sign(dst-r)==0)return 1;
return 0;
}
int relationline(Line v){
db dst=v.dispointtoline(p);
if(sign(dst-r)<0)return 2;
else if(sign(dst-r)==0)return 1;
return 0;
}
//|1 内含|2 内切|3 相交|4 外切|5 相离|
int relationcircle(circle v){
db d=p.distance(v.p);
if(sign(d-r-v.r)>0)return 5;
if(sign(d-r-v.r)==0)return 4;
db l=fabs(r-v.r);
if(sign(d-r-v.r)<0&&sign(d-l)>0)return 3;
if(sign(d-l)==0)return 2;
if(sign(d-l)<0)return 1;
}
//|0 没有交点|1 一个交点|2 两个交点|
int pointcrosscircle(circle v,Point &p1,Point &p2){
int rel=relationcircle(v);
if(rel==1||rel==5)return 0;
db d=p.distance(v.p);
db l=(d*d+r*r-v.r*v.r)/(2*d);
db h=sqrt(r*r-l*l);
Point tmp=p+(v.p-p).trunc(l);
p1 = tmp+((v.p-p).rotleft().trunc(h));
p2 = tmp+((v.p-p).rotright().trunc(h));
if(rel==2||rel==4)return 1;
return 2;
}
int pointcrossline(Line v,Point &p1,Point &p2){
if(!(*this).relationline(v))return 0;
Point a=v.lineprog(p);
db d=v.dispointtoline(p);
d=sqrt(r*r-d*d);
if(sign(d)==0){
p1=a;p2=a;
return 1;
}
p1=a+(v.e-v.s).trunc(d);
p2=a-(v.e-v.s).trunc(d);
return 2;
}
int getcircle(Point a,Point b,db r1,circle &c1,circle &c2){
circle x(a,r1),y(b,r1);
int t=x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r=c2.r=r;
return t;
}
int getcircle(Line u,Point q,db r1,circle &c1,circle &c2){
db dis=u.dispointtoline(q);
if(sign(dis-r1*2)>0)return 0;
if(sign(dis)==0){
c1.p=q+((u.e-u.s).rotleft().trunc(r1));
c2.p=q+((u.e-u.s).rotright().trunc(r1));
c1.r=c2.r=r1;
return 2;
}
Line u1=Line((u.s+(u.e-u.s).rotleft().trunc(r1)),(u.e+(u.e-u.s).rotleft().trunc(r1)));
Line u2=Line((u.s+(u.e-u.s).rotright().trunc(r1)),(u.e+(u.e-u.s).rotright().trunc(r1)));
circle cc = circle(q,r1);
Point p1,p2;
if(!cc.pointcrossline(u1,p1,p2))cc.pointcrossline(u2,p1,p2);
c1 = circle(p1,r1);
if(p1 == p2){
c2 = c1;
return 1;
}
c2 = circle(p2,r1);
return 2;
}
int getcircle(Line u,Line v,db r1,circle &c1,circle &c2,circle &c3,circle &c4){
if(u.parallel(v))return 0;//两直线平行
Line u1=Line(u.s+(u.e-u.s).rotleft().trunc(r1),u.e+(u.e-u.s).rotleft().trunc(r1));
Line u2=Line(u.s+(u.e-u.s).rotright().trunc(r1),u.e+(u.e-u.s).rotright().trunc(r1));
Line v1=Line(v.s+(v.e-v.s).rotleft().trunc(r1),v.e+(v.e-v.s).rotleft().trunc(r1));
Line v2=Line(v.s+(v.e-v.s).rotright().trunc(r1),v.e+(v.e-v.s).rotright().trunc(r1));
c1.r=c2.r=c3.r=c4.r=r1;
c1.p=u1.crosspoint(v1);
c2.p=u1.crosspoint(v2);
c3.p=u2.crosspoint(v1);
c4.p=u2.crosspoint(v2);
return 4;
}
int getcircle(circle cx,circle cy,db r1,circle &c1,circle &c2){
circle x(cx.p,r1+cx.r),y(cy.p,r1+cy.r);
int t=x.pointcrosscircle(y,c1.p,c2.p);
if(!t)return 0;
c1.r=c2.r=r1;
return t;
}
int tangentline(Point q,Line &u,Line &v){
int x = relation(q);
if(x == 2)return 0;
if(x == 1){
u = Line(q,q + (q-p).rotleft());
v = u;
return 1;
}
db d = p.distance(q);
db l = r*r/d;
db h = sqrt(r*r-l*l);
u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h)));
v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h)));
return 2;
}
db areacircle(circle v){
int rel = relationcircle(v);
if(rel >= 4)return 0.0;
if(rel <= 2)return min(area(),v.area());
db d = p.distance(v.p);
db hf = (r+v.r+d)/2.0;
db ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
db a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
a1 = a1*r*r;
db a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
a2 = a2*v.r*v.r;
return a1+a2-ss;
}
db areatriangle(Point a,Point b){
if(sign((p-a)^(p-b)) == 0)return 0.0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a,b);
Point p1,p2;
if(pointcrossline(l,q[1],q[2])==2){
if(sign((a-q[1])*(b-q[1]))<0)q[len++] = q[1];
if(sign((a-q[2])*(b-q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sign((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
db res = 0;
for(int i = 0;i < len-1;i++){
if(relation(q[i])==0||relation(q[i+1])==0){
db arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
}
else{
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
};
int getTangents(circle A,circle B,Point *a,Point *b)
{
int cnt=0; //存切点用
if(sign(A.r-B.r)<0){
swap(A,B);
swap(a,b);
}
db d=sqrt((A.p.x-B.p.x)*(A.p.x-B.p.x)+(A.p.y-B.p.y)*(A.p.y-B.p.y)); //圆心距
db rdiff=A.r-B.r; //两圆半径差
db rsum=A.r+B.r; //两圆半径和
if(sign(d-rdiff)<0)return 0; //1.内含
db base=atan2(B.p.y-A.p.y,B.p.x-A.p.x); //向量AB的极角
if(sign(d)== 0)return -1; //2.重合
if(sign(d-rdiff) == 0){
//3.内切
a[cnt]=b[cnt]=A.point(base);
cnt++;
return 1;
}
db ang=acos((A.r-B.r)/d);
a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang);cnt++; //4.相交(外切、外离的外公切线也在此求出)
a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang);cnt++; //两条外公切线的切点
if(sign(d-rsum)==0){
//5.外切
a[cnt]=b[cnt]=A.point(base);
cnt++;
}
else if(sign(d-rsum)>0){
//6.外离
db ang=acos((A.r+B.r)/d);
a[cnt]=A.point(base+ang);b[cnt]=B.point(PI+base+ang);cnt++;
a[cnt]=A.point(base-ang);b[cnt]=B.point(PI+base-ang);cnt++;
}
return cnt;
}
struct polygon{
int n;
Point p[N];
Line l[N];
void input(int _n){
n=_n;
rep(i,0,n-1)p[i].input();
}
void add(Point q){
p[n++]=q;}
void getline(){
rep(i,0,n-1)l[i]=Line(p[i],p[(i+1)%n]);}
struct cmp{
Point p;
cmp(const Point &p0){
p = p0;}
bool operator()(const Point &aa,const Point &bb){
Point a = aa, b = bb;
int d = sign((a-p)^(b-p));
if(d == 0){
return sign(a.distance(p)-b.distance(p)) < 0;
}
return d > 0;
}
};
//极角排序
void norm(){
Point mi=p[0];
rep(i,1,n-1)mi=min(mi,p[i]);
sort(p,p+n,cmp(mi));
}
//`得到的凸包里面的点编号是[0,n-1]的`
//`注意如果有影响,要特判下所有点共点,或者共线的特殊情况`
void getconvex(polygon &convex){
sort(p,p+n);
convex.n=n;
rep(i,0,min(n,2)-1)convex.p[i]=p[i];
if(convex.n==2&&(convex.p[0]==convex.p[1]))convex.n--;//特判
if(n<=2)return;
int &top=convex.n;
top=1;
rep(i,2,n-1){
while(top&&sign((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)top--;
convex.p[++top] = p[i];
}
int temp=top;
convex.p[++top]=p[n-2];
per(i,n-3,0){
while(top!=temp&&sign((convex.p[top]-p[i])^(convex.p[top-1]-p[i]))<=0)top--;
convex.p[++top]=p[i];
}
if(convex.n==2&&(convex.p[0]==convex.p[1]))convex.n--;//特判
convex.norm();//`原来得到的是顺时针的点,排序后逆时针`
}
//`得到凸包的另外一种方法`
void Graham(polygon &convex){
norm();
int &top=convex.n;
top=0;
if(n==1){
top=1;
convex.p[0]=p[0];
return;
}
if(n==2){
top=2;
convex.p[0]=p[0];
convex.p[1]=p[1];
if(convex.p[0]==convex.p[1])top--;
return;
}
convex.p[0]=p[0];
convex.p[1]=p[1];
top=2;
rep(i,2,n-1){
while(top>1&&sign((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0)top--;
convex.p[top++]=p[i];
}
if(convex.n==2&&(convex.p[0]==convex.p[1]))convex.n--;//特判
}
//`判断是不是凸的`
bool isconvex(){
bool s[2];
memset(s,false,sizeof(s));
rep(i,0,n-1){
int j=(i+1)%n;
int k=(j+1)%n;
s[sign((p[j]-p[i])^(p[k]-p[i]))+1]=true;
if(s[0]&&s[2])return false;
}
return true;
}
//`判断点和任意多边形的关系`
//|` 0 外部`|` 1 内部`|` 2 边上`|` 3 点上`|
int relationpoint(Point q){
rep(i,0,n-1){
if(p[i]==q)return 3;
}
getline();
rep(i,0,n-1){
if(l[i].pointonseg(q))return 2;
}
int cnt=0;
rep(i,0,n-1){
int j=(i+1)%n;
int k=sign((q-p[j])^(p[i]-p[j]));
int u=sign(p[i].y-q.y);
int v=sign(p[j].y-q.y);
if(k>0&&u<0&&v>=0)cnt++;//逆时针穿过+1
if(k<0&&v<0&&u>=0)cnt--;//顺时针穿过-1
}
return cnt!=0;
}
//`直线u切割凸多边形左侧`
//`注意直线方向`
void convexcut(Line u,polygon &po){
int &top = po.n;//注意引用
top = 0;
for(int i = 0;i < n;i++){
int d1 = sign((u.e-u.s)^(p[i]-u.s));
int d2 = sign((u.e-u.s)^(p[(i+1)%n]-u.s));
if(d1 >= 0)po.p[top++] = p[i];
if(d1*d2 < 0)po.p[top++] = u.crosspoint(Line(p[i],p[(i+1)%n]));
}
}
// //`得到周长`
// //`测试 LightOJ1239`
db getcircumference(){
db sum = 0;
for(int i = 0;i < n;i++){
sum += p[i].distance(p[(i+1)%n]);
}
return sum;
}
//`得到面积`
db getarea(){
db sum = 0;
for(int i = 0;i < n;i++){
sum += (p[i]^p[(i+1)%n]);
}
return fabs(sum)/2;
}
// //`得到方向`
// //` 1 表示逆时针,0表示顺时针`
bool getdir(){
db sum = 0;
for(int i = 0;i < n;i++)
sum += (p[i]^p[(i+1)%n]);
if(sign(sum) > 0)return 1;
return 0;
}
// //`得到重心`
Point getbarycentre(){
Point ret(0,0);
db area = 0;
for(int i = 1;i < n-1;i++){
db tmp = (p[i]-p[0])^(p[i+1]-p[0]);
if(sign(tmp) == 0)continue;
area += tmp;
ret.x += (p[0].x+p[i].x+p[i+1].x)/3*tmp;
ret.y += (p[0].y+p[i].y+p[i+1].y)/3*tmp;
}
if(sign(area)) ret = ret/area;
return ret;
}
// //`多边形和圆交的面积`
db areacircle(circle c){
db ans = 0;
for(int i = 0;i < n;i++){
int j = (i+1)%n;
if(sign( (p[j]-c.p)^(p[i]-c.p) ) >= 0)
ans += c.areatriangle(p[i],p[j]);
else ans -= c.areatriangle(p[i],p[j]);
}
return fabs(ans);
}
//`多边形和圆关系`
//` 2 圆完全在多边形内`
//` 1 圆在多边形里面,碰到了多边形边界`
//` 0 其它`
int relationcircle(circle c){
getline();
int x = 2;
if(relationpoint(c.p) != 1)return 0;//圆心不在内部
for(int i = 0;i < n;i++){
if(c.relationseg(l[i])==2)return 0;
if(c.relationseg(l[i])==1)x = 1;
}
return x;
}
};
//旋转卡壳,计算凸包直径
db RC(polygon v)
{
db res=0;
int n=v.n;
int k=1;
rep(i,0,n-1){
while(sign(cross(v.p[i],v.p[(i+1)%n],v.p[(k+1)%n])-cross(v.p[i],v.p[(i+1)%n],v.p[k%n]))==1)k=(k+1)%n;
res=max(res,max((v.p[i]-v.p[k]).len(),(v.p[(i+1)%n]-v.p[k]).len()));
}
return res;
}
//`最小矩形面积覆盖`
//` A 必须是凸包(而且是逆时针顺序)`
db minRectangleCover(polygon A){
//`要特判A.n < 3的情况`
if(A.n < 3)return 0.0;
A.p[A.n] = A.p[0];
db ans = -1;
int r = 1, p = 1, q;
for(int i = 0;i < A.n;i++){
//`卡出离边A.p[i] - A.p[i+1]最远的点`
while( sign( cross(A.p[i],A.p[i+1],A.p[r+1]) - cross(A.p[i],A.p[i+1],A.p[r]) ) >= 0 )
r = (r+1)%A.n;
//`卡出A.p[i] - A.p[i+1]方向上正向n最远的点`
while(sign( dot(A.p[i],A.p[i+1],A.p[p+1]) - dot(A.p[i],A.p[i+1],A.p[p]) ) >= 0 )
p = (p+1)%A.n;
if(i == 0)q = p;
//`卡出A.p[i] - A.p[i+1]方向上负向最远的点`
while(sign(dot(A.p[i],A.p[i+1],A.p[q+1]) - dot(A.p[i],A.p[i+1],A.p[q])) <= 0)
q = (q+1)%A.n;
db d = (A.p[i] - A.p[i+1]).len2();
db tmp = cross(A.p[i],A.p[i+1],A.p[r]) *
(dot(A.p[i],A.p[i+1],A.p[p]) - dot(A.p[i],A.p[i+1],A.p[q]))/d;
if(ans < 0 || ans > tmp)ans = tmp;
}
return ans;
}
//`直线切凸多边形`
//`多边形是逆时针的,在q1q2的左侧`
//`测试:HDU3982`
vector<Point> convexCut(const vector<Point> &ps,Point q1,Point q2){
vector<Point>qs;
int n = ps.size();
for(int i = 0;i < n;i++){
Point p1 = ps[i], p2 = ps[(i+1)%n];
int d1 = sign((q2-q1)^(p1-q1)), d2 = sign((q2-q1)^(p2-q1));
if(d1 >= 0)
qs.push_back(p1);
if(d1 * d2 < 0)
qs.push_back(Line(p1,p2).crosspoint(Line(q1,q2)));
}
return qs;
}
int n,casen=1;
polygon g,r;
db sumx,sumy,a,b,c;
int main()
{
#ifdef io
freopen("in.txt","r",stdin);
#endif
rush(){
sc(n);
g.n=0;
sumx=sumy=0;
rep(i,1,n){
g.p[g.n++].input();
sumx+=g.p[i-1].x;
sumy+=g.p[i-1].y;
}
g.getconvex(r);
db ans=inf;
if(r.n<=2)ans=0;
else{
rep(i,0,r.n-1){
Point p1=r.p[i],p2=r.p[(i+1)%(r.n)];
a=p2.y-p1.y;
b=p1.x-p2.x;
c=-a*p1.x-b*p1.y;
ans=min(ans,fabs(a*sumx+b*sumy+c*n)/sqrt(a*a+b*b));
}
}
printf("Case #%d: %.3f\n",casen++,ans/n);
}
return 0;
}