【题目地址-loj】
题意见题面。
我们知道,在计算几何中,我们可以用叉积来表示三角形面积,于是我们可以设站的点为 ( x , y ) (x,y) (x,y),凸边形的顶点为 ( x 0 , y 0 ) ∼ ( x n − 1 , y n − 1 ) (x_0,y_0)\sim (x_{n-1},y_{n-1}) (x0,y0)∼(xn−1,yn−1),那么根据题意我们可以得到 n − 1 n-1 n−1个不等式:
( x 0 − x ) ( y 1 − y ) − ( y 0 − y ) ( x 1 − x ) ≤ ( x k − x ) ( y k + 1 − y ) − ( y k − y ) ( x k + 1 − x ) (x_0-x)(y_1-y)-(y_0-y)(x_1-x)\leq (x_k-x)(y_{k+1}-y)-(y_k-y)(x_{k+1}-x) (x0−x)(y1−y)−(y0−y)(x1−x)≤(xk−x)(yk+1−y)−(yk−y)(xk+1−x)
将其化简为 a x + b x + c = 0 ax+bx+c=0 ax+bx+c=0的形式:
( y 0 − y 1 − y k + y k + 1 ) x + ( x 1 − x 0 − x k + 1 + x k ) y + ( x 0 y 1 − x 1 y 0 − x k y k + 1 + x k + 1 y k ) ≤ 0 (y_0-y_1-y_k+y_{k+1})x+(x_1-x_0-x_{k+1}+x_k)y+(x_0y_1-x_1y_0-x_ky_{k+1}+x_{k+1}y_k)\leq 0 (y0−y1−yk+yk+1)x+(x1−x0−xk+1+xk)y+(x0y1−x1y0−xkyk+1+xk+1yk)≤0
然后用半平面交就可以求出解的范围大小,用交的面积除以凸边形总面积便是答案。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define db double
using namespace std;
const int M=2e5+10;
const db eps=1e-10;
int dcmp(db x){if(fabs(x)<eps) return 0;return x<0?-1:1;}
int n,cnt;
db intot,ans;
struct point{
db x,y;
void in(){scanf("%lf%lf",&x,&y);}
point(){}
point(db a,db b):x(a),y(b){}
}p[M];
point operator +(point a,point b){return point(a.x+b.x,a.y+b.y);}
point operator -(point a,point b){return point(a.x-b.x,a.y-b.y);}
point operator *(point a,db b){return point(a.x*b,a.y*b);}
point operator /(point a,db b){return point(a.x/b,a.y/b);}
db cross(point a,point b){return a.x*b.y-a.y*b.x;}
struct line{
point a,v;
db arc;
line(){}
line(point x,point y):a(x),v(y){arc=atan2(v.y,v.x);}
bool operator <(line b)const{
if(fabs(arc-b.arc)>eps)
return arc<b.arc;
return cross(v,b.a-a)<0;
}
}l[M],q[M];
point getcut(line a,line b){
point u=a.a-b.a;
db t=cross(b.v,u)/cross(a.v,b.v);
return a.a+a.v*t;
}
bool isonleft(line a,point b){return cross(a.v,b-a.a)>0;}
int halfcross(){
int fi=1,la=1;
q[1]=l[1];p[1]=p[0]=p[2]=p[3]=point(0,0);
for(int i=2;i<=cnt;i++){
while(fi<la&&!isonleft(l[i],p[la-1])) la--;
while(fi<la&&!isonleft(l[i],p[fi])) fi++;
q[++la]=l[i];
if(fi<la) p[la-1]=getcut(q[la-1],q[la]);
}
while(fi<la&&!isonleft(q[fi],p[la-1])) la--;
p[la]=getcut(q[la],q[fi]);
for(int i=fi;i<=la;i++)p[i-fi+1]=p[i];
p[la-fi+2]=p[1];
return la-fi+1;
}
int main(){
freopen("convex.in","r",stdin);
freopen("convex.out","w",stdout);
scanf("%d",&n);
p[1].in();p[2].in();p[n+1]=p[1];
db tt=p[1].y*p[2].x-p[1].x*p[2].y;
for(int i=3;i<=n+1;i++){
if(i<=n)p[i].in();
int j=i-1;
db a=p[1].y-p[2].y-p[j].y+p[i].y;
db b=p[2].x-p[1].x-p[i].x+p[j].x;
db c=tt+p[j].x*p[i].y-p[i].x*p[j].y;c*=-1;
l[++cnt]=line(fabs(a)>eps?point(-c/a,0):point(0,-c/b),point(-b,a));
}
for(int i=1;i<=n;i++) intot+=cross(p[i],p[i+1]);
for(int i=1;i<=n;i++) l[++cnt]=line(p[i],p[i+1]-p[i]);
int tot=0;
sort(l+1,l+cnt+1);
for(int i=1;i<=cnt;i++){
if(dcmp(l[i].arc-l[i-1].arc)!=0||i==1) l[++tot]=l[i];
} cnt=tot;tot=halfcross();
if(tot<3){printf("0.0000\n");return 0;}
for(int i=1;i<=tot;i++)ans+=cross(p[i],p[i+1]);
intot=fabs(intot);ans=fabs(ans);
printf("%.4lf\n",ans/intot);
fclose(stdin);
fclose(stdout);
return 0;
}