1. 程式人生 > >【BZOJ4445】[Scoi2015]小凸想跑步 半平面交

【BZOJ4445】[Scoi2015]小凸想跑步 半平面交

三角形 hint 表示 ios light sum 跑步 des 有時

【BZOJ4445】[Scoi2015]小凸想跑步

Description

小凸晚上喜歡到操場跑步,今天他跑完兩圈之後,他玩起了這樣一個遊戲。 操場是個凸n邊形,N個頂點按照逆時針從0~n-l編號。現在小凸隨機站在操場中的某個位置,標記為P點。將P點與n個頂點各連一條邊,形成N個三角形。如果這時P點,0號點,1號點形成的三角形的面積是N個三角形中最小的一個,小凸則認為這是一次正確站位。 現在小凸想知道他一次站位正確的概率是多少。

Input

第1行包含1個整數n,表示操場的頂點數和遊戲的次數。 接下來有N行,每行包含2個整數Xi,Yi表示頂點的坐標。 輸入保證按逆時針順序輸入點,所有點保證構成一個n多邊形。所有點保證不存在三點共線。

Output

輸出1個數,正確站位的概率,保留4位小數。

Sample Input

5
1 8
0 7
0 0
8 0
8 8

Sample Output

0.6316

HINT

3<=N<=10^5,-10^9<=X,Y<=10^9

題解:現在才發現,我有時喜歡用一條直線的左邊來代表一個半平面,有時喜歡用一條直線的右面代表一個半平面。。不過無所謂啦~

題中的限制是三角形面積的大小關系,如果我們將三角形面積用叉積來表示的話很容易將所給條件變成n-1個不等式,外加n個不等式限定P在多邊形內部。求半平面交即可。

至於精度。。。用long double,把eps刪掉即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=200010;
typedef long double db;
struct point
{
	db x,y;
	point() {}
	point(db a,db b) {x=a,y=b;}
	point operator + (const point &a) const {return point(x+a.x,y+a.y);}
	point operator - (const point &a) const {return point(x-a.x,y-a.y);}
	point operator * (const db &a) const {return point(x*a,y*a);}
	db operator * (const point &a) const {return x*a.y-y*a.x;}
}p[maxn];
struct line
{
	point p,v;
	db a;
	line() {}
	line(point x,point y) {p=x,v=y,a=atan2(v.y,v.x);}
}l[maxn];
int n,tot,h,t;
db ans,sum;
int q[maxn];
inline bool onlft(line a,point b)
{
	return a.v*(b-a.p)>=0;
}
inline point getp(line a,line b)
{
	point u=a.p-b.p;
	db tmp=(b.v*u)/(a.v*b.v);
	return a.p+a.v*tmp;
}
inline bool cmp(const line &a,const line &b)
{
	if(fabs(a.a-b.a)==0)	return onlft(a,b.p);
	return a.a<b.a;
}
inline void HPI()
{
	sort(l+1,l+tot+1,cmp);
	int i,j=1;
	for(i=2;i<=tot;i++)	if(fabs(l[i].a-l[j].a)>0)	l[++j]=l[i];
	tot=j;
	h=1,t=2,q[1]=1,q[2]=2;
	for(i=3;i<=tot;i++)
	{
		while(h<t&&onlft(l[i],getp(l[q[t-1]],l[q[t]])))	t--;
		while(h<t&&onlft(l[i],getp(l[q[h+1]],l[q[h]])))	h++;
		q[++t]=i;
	}
	while(h<t&&onlft(l[q[h]],getp(l[q[t-1]],l[q[t]])))	t--;
	for(i=h;i<t;i++)	p[i]=getp(l[q[i]],l[q[i+1]]);
	p[t]=getp(l[q[t]],l[q[h]]);
	for(i=h;i<t;i++)	ans+=p[i]*(p[i+1]-p[i]);
	ans+=p[t]*(p[h]-p[t]);
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i;
	for(i=0;i<n;i++)	p[i].x=rd(),p[i].y=rd();
	p[n]=p[0];
	for(i=0;i<n;i++)	l[++tot]=line(p[i+1],p[i]-p[i+1]),sum+=p[i]*(p[i+1]-p[i]);
	for(i=1;i<n;i++)
	{
		db a=p[i+1].x-p[i].x-p[1].x+p[0].x;
		db b=p[i+1].y-p[i].y-p[1].y+p[0].y;
		db c=-(p[i]*(p[i+1]-p[i]))+(p[0]*(p[1]-p[0]));
		if(fabs(a)>0)	l[++tot]=line(point(0,c/a),point(-a,-b));
		else	if(fabs(b)>0)	l[++tot]=line(point(-c/b,0),point(0,-b));
	}
	HPI();
	printf("%.4lf",(double)fabs(ans/sum));
	return 0;
}

【BZOJ4445】[Scoi2015]小凸想跑步 半平面交