scoiday1T3&&bzoj4445小凸想跑步

幾何題啊,據說是裸的半平面交,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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章