wwwwwwwwwwwwwwwwwww
我已经不知道这串w是什么意思了
一开始以为是什么高大上的东西,钻研了会$P$点的性质。后来发现就是列个式子的事。
三角形的面积,两边叉积的一半,把这个叉积写开:
$\overrightarrow{PP_i}\times\overrightarrow{PP_{i+1}}$
$=(p_i-p)\times(p_{i+1}-p)$
$=p_i\times p_{i+1}-p_i\times p-p\times p_{i+1}$
$=x(y_i-y_{i+1})+y(x_{i+1}-x_i)+p_i\times p_{i+1}$
再把条件“$p_0,p_1,p$围成的三角形面积最小”写开:
$\overrightarrow{PP_i}\times\overrightarrow{PP_{i+1}}>\overrightarrow{PP_0}\times\overrightarrow{PP_1}$
$x(y_i-y_{i+1})+y(x_{i+1}-x_i)+p_i\times p_{i+1}>x(y_0-y_1)-y(x_1-x_0)+p_0\times p_1$
$x(y_i-y_{i+1}-y_0+y_1)+y(x_{i+1}-x_i-x_1+x_0)+p_i\times p_{i+1}-p_0\times p_1>0$
半平面交显然。由于点$P$要在凸多边形内,还要和凸多边形交一下。答案算个面积之比就好了。
然而很玄学的是不能直接代$x=0,1$(或者$y=0,1$)表示直线,貌似是因为坐标太大叉乘就炸了。然而代$x=0$和$x=0$加上向量$(b,-a)$就过了。。。
感觉两种方法没有本质上的区别啊,有没有大佬解释一下啊。。。
这题好就好在不怎么卡精度,开个long double
就过了,甚至可以不设eps
直接比。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define maxn 200005
#define double long double
const double eps = 1e-18;
const double inf = 1e18;
const double pi = acos(-1.0);
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
inline int cmp(double x,double y){return x-y>eps?1:x-y<-eps?-1:0;}
struct point{
double x,y;
point(double X=0,double Y=0){x=X,y=Y;}
point operator + (const point &a){return point(x+a.x,y+a.y);}
point operator - (const point &a){return point(x-a.x,y-a.y);}
point operator * (const double &a){return point(x*a,y*a);}
point operator / (const double &a){return point(x/a,y/a);}
double alpha(){return atan2(y,x);}
}p[maxn],P;
struct line{
point a,b;
double an;
line(point A=point(0,0),point B=point(0,0)){a=A,b=B,an=(b-a).alpha();}
}l[maxn],q[maxn];
struct circle{
point c;
double r;
circle(point C=point(0,0),double R=0){c=C,r=R;}
circle(point A,point B,point C){
#define sqr(x) ((x)*(x))
double a=sqr(A.x)-sqr(B.x)+sqr(A.y)-sqr(B.y),b=sqr(B.x)-sqr(C.x)+sqr(B.y)-sqr(C.y),_c=A.x-B.x,d=A.y-B.y,e=B.x-C.x,f=B.y-C.y,m=2*(_c*f-d*e);
c=point((a*f-b*d)/m,(b*_c-a*e)/m);
r=sqrt(sqr(A.x-c.x)+sqr(A.y-c.y));
#undef sqr
}
};
typedef vector<point> polygon;
inline double abs2(point a){return a.x*a.x+a.y*a.y;}
inline double abs(point a){return sqrt(abs2(a));}
inline double dis(point &a,point &b){return abs(a-b);}
inline double dot(point a,point b){return a.x*b.x+a.y*b.y;}
inline double cross(point a,point b){return a.x*b.y-a.y*b.x;}
inline double angle(line &a){return (a.b-a.a).alpha();}
inline point rotate(point a,double b){return point(a.x*cos(b)-a.y*sin(b),a.x*sin(b)+a.y*cos(b));}
inline point inter(line a,line b){
point A=a.b-a.a,B=b.b-b.a;
return a.a+A*cross(B,a.a-b.a)/cross(A,B);
}
inline double area(polygon &a){
double ans=0;
for(register int i=0,j=a.size()-1;i<a.size();j=i++)ans+=cross(a[j],a[i]);
return ans/2.0;
}
polygon u,v;
inline bool mmp(line &a,line &b){
if(a.an==b.an)return cross(b.b-a.a,b.a-a.a)<0.0;
return a.an<b.an;
}
inline bool judge(point &a,line &b){return cross(b.b-a,b.a-a)>0.0;}
int main(){
int n=read(),cnt=0,h=1,t=0;
for(register int i=1;i<=n;++i){
P.x=read(),P.y=read();
v.push_back(P);
}
for(register int i=0,j=n-1;i<n;j=i++){
l[++cnt]=line(v[j],v[i]);
if(i==1)continue;
double a=v[j].y-v[i].y-v[0].y+v[1].y,b=v[i].x-v[j].x-v[1].x+v[0].x,c=cross(v[j],v[i])-cross(v[0],v[1]);
if(cmp(a,0))l[++cnt]=line(point(-c/a,0),point(-c/a+b,-a));
else if(cmp(b,0))l[++cnt]=line(point(0,-c/b),point(b,-c/b-a));
}
sort(l+1,l+1+cnt,mmp);
for(register int i=1;i<=cnt;++i){
if(i!=1&&angle(l[i])==angle(l[i-1]))continue;
while(t-h>=1&&judge(p[t],l[i]))--t;
while(t-h>=1&&judge(p[h+1],l[i]))++h;
q[++t]=l[i];
if(t-h>=1)p[t]=inter(q[t],q[t-1]);
}
while(t-h>=1&&judge(p[t],q[h]))--t;
u.push_back(inter(q[h],q[t]));
for(register int i=h+1;i<=t;++i)u.push_back(p[i]);
printf("%.4Lf\n",area(u)/area(v));
}