幾何題啊,據說是裸的半平面交,but我還是WA了好幾發。
逆時針給定一些點,求多邊形內到第一條邊面積比到其它邊小的點的概率(用範圍/總面積)
然後可以設該點爲(x,y),到所有邊的面積表示出來,然後建立不等關係,化簡約分後我們可以得到一系列關於x,y的不等式,形如ax+by<c,然後就搞一搞半平面交。
然而有兩個bug我沒考慮到,一個就是要保證(x,y)的點在凸多邊形內部,怎麼保證?先把所有的半平面表示成直線,直線左側表示半平面,然後所有邊加進來,也構成一串不等關係。
我沒考慮這種情況,所出來概率偏大,爲什麼? 因爲這個點的範圍到了多邊形外側啊。
上面一種方案對應第一種,空間是第二種的兩倍,時間差不多也是.
那第二種怎麼搞,我們可以只把第一條邊的限制加進去,其餘邊都不管,爲什麼這麼做是可行的呢? 可以感性的理解一下,如果在其他邊外側,它一定不可能是到第一條邊最小了,所以在不等關係的約束條件之外,根本就搞不動了。(可以適當畫圖驗證)
這樣的時間和空間都節省了。
第二個bug然我搞了很久,因爲之前樣例已經可以過了,然而交了幾發都WA了(又貢獻了這麼多個WA,真是汗顏!)
後來不斷生成數據(其實最後是自己手推了一組數據),發現自己的輸出居然是"nan",恩,一定是哪裏掛了,然後我把數據帶進去調試,發現我計算不等關係ax+by+c<0的時候,b有可能爲0了,這種情況下我用的起始點分母有個b,就除以了0,就非法了,然後就GG了。
調出第二個bug之後果斷又來了一發,結果就A了.
然後無聊就來找找出bug的原因(又交了幾發,又WA了幾次)。
在第一個bug中,如果要所有邊建立不等式需要把空間開成2倍。
搞出了一系列不等關係,直接套一下半平面交。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define eps 1e-10
using namespace std;
const int maxn=200000+20;
int dcmp(double x)
{
if(fabs(x)<eps)return 0;
else return x<0?-1:1;
}
struct point
{
double x,y;
point(){}
point(double _x,double _y){x=_x;y=_y;}
point operator +(const point &b){return point(x+b.x,y+b.y);}
point operator -(const point &b){return point(x-b.x,y-b.y);}
point operator *(const double &b){return point(x*b,y*b);}
};
struct line
{
point p,v;
double ang;
line(){}
line(point _p,point _v){p=_p;v=_v;ang=atan2(v.y,v.x);}
bool operator <(const line &l)const
{
return ang<l.ang;
}
};
double cross(point a,point b){return a.x*b.y-a.y*b.x;}
double dot(point a,point b){return a.x*b.x+a.y*b.y;}
bool onleft(line l,point p){return dcmp(cross(l.v,p-l.p))>0;}
/*
(y1+y4-y2-y3)x+(x2+x3-x1-x4)y+x1y2-x2y1+x4y3-x3y4<0
*/
point getsec(point p1,point v1,point p2,point v2)
{
double x=cross(p2-p1,v2)/cross(v1,v2);
return p1+v1*x;
}
double pans;
line l[maxn];
point t[maxn];
line q[maxn];
void Hp(line *L,int n)
{
sort(L+1,L+n+1);
int first,last;
point p[maxn];
q[last=first=0]=L[1];
for(int i=2;i<=n;i++)
{
while(first<last&&!onleft(L[i],p[last-1]))last--;
while(first<last&&!onleft(L[i],p[first]))first++;
q[++last]=L[i];
if(dcmp(cross(q[last].v,q[last-1].v))==0)
{
last--;
if(!onleft(L[i],p[last-1]))q[last]=L[i];
//等價於if(onleft(q[last],L[i].p))q[last]=L[i];
}
if(first<last)p[last-1]=getsec(q[last].p,q[last].v,q[last-1].p,q[last-1].v);
}
while(first<last&&!onleft(q[first],p[last-1]))last--;
if(last-first<=1)
{
printf("0.0000\n");
return ;
}
p[last]=getsec(q[last].p,q[last].v,q[first].p,q[first].v);
double ans=0;
for(int i=first+1;i<last;i++)
{
ans+=fabs(cross(p[i]-p[first],p[i+1]-p[first]));
}
ans*=0.5;
printf("%.4lf\n",ans/pans);
}
int cnt;
void pre(int n)
{
cnt=0;
double x1=t[1].x,y1=t[1].y;
double x2=t[2].x,y2=t[2].y;
for(int i=2;i<=n;i++)
{
double x3=t[i].x,y3=t[i].y;
double x4=t[i+1].x,y4=t[i+1].y;
double a=y1+y4-y2-y3;
double b=x2+x3-x1-x4;
double c=x1*y2-x2*y1+x4*y3-x3*y4;
//ax+by+c<0
//方向向量(-b,a);
//使得ax+by+c=0左邊表示ax+by+c
point p;if(dcmp(b)!=0)p=point(0,-c/b);
else p=point(-c/a,0);
point v;v=point(-b,a);
l[++cnt]=line(p,v);
}
//l[++cnt]=line(t[1],t[2]-t[1]);//
for(int i=1;i<=n;i++)l[++cnt]=line(t[i],t[i+1]-t[i]);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lf%lf",&t[i].x,&t[i].y);
pans=0;
for(int i=2;i<n;i++)
{
pans+=fabs(cross(t[i]-t[1],t[i+1]-t[1]));
}
pans*=0.5;
t[n+1]=t[1];
pre(n);
Hp(l,cnt);
return 0;
}