小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏。
操场是个凸n边形,N个顶点按照逆时针从0~n-l编号。现在小凸随机站在操场中的某个位置,标记为
P点。将P点与n个顶点各连一条边,形成N个三角形。如果这时P点,0号点,1号点形成的三角形的面
积是N个三角形中最小的一个,小凸则认为这是一次正确站位。
现在小凸想知道他一次站位正确的概率是多少。
3<=N<=10^5,-10^9<=X,Y<=10^9
设小凸站的位置的坐标为(x,y),那么对于操场的每一条边,可以用叉积列出三角形的面积计算式
要求是三角形P01的面积最小,那么就可以列出n - 1个不等式,每个不等式有类似的形式
随意拿出一个算一下就能发现最终都能化成一个半平面的表达式,写个半平面交就行了
不过要注意最终交出来的多边形一定要在原多边形内部
为了满足这个限制,其实把边01加入半平面集合就够了,其它边倒是不一定加
因为其它边的限制倘若不满足,显然已经不满足P01面积最小的条件了,
一开始的n - 1个平面的交集就肯定能满足这个限制
因为苟蒻用的求半平面交的方法是用向量的左侧表示半平面
所以要把不等关系转换成向量
随意随机几个点。。。叉积瞎判一下吧?好像这样很蠢。。。
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1E5 + 10;
typedef double DB;
const DB EPS = 1E-8;
struct Point{
DB x,y; Point(){}
Point(DB x,DB 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 DB &t) {return Point(x * t,y * t);}
}D[maxn],sec[maxn];
typedef Point Vector;
struct Line{
Point p; Vector v; DB ang; Line(){}
Line(Point p,Vector v): p(p),v(v){ang = atan2(v.y,v.x);}
bool operator < (const Line & B) const {return ang < B.ang;}
}L[maxn],s[maxn];
int n,tot,head,tail;
DB Cross(Vector v1,Vector v2) {return v1.x * v2.y - v2.x * v1.y;}
bool OnLeft(Point p,Line L) {return Cross(L.v,p - L.p) > 0;}
Point GetIntersection(Line L1,Line L2)
{
Vector u = L2.p - L1.p;
DB t = Cross(u,L2.v) / Cross(L1.v,L2.v);
return L1.p + L1.v * t;
}
void Insert(DB a,DB b,DB c)
{
DB r1,c1,r2,c2,x,y;
r1 = 233.37; r2 = 137.68;
if (fabs(b) <= EPS) r1 = r2 = -c / a,c1 = 120.23,c2 = 349.27;
else c1 = -(c + a * r1) / b,c2 = -(c + a * r2) / b;
for (;;)
{
x = rand() % 2333333; y = rand() % 2333333;
if (fabs(a * x + b * y + c) > EPS) break;
}
bool f1 = a * x + b * y + c < 0 ? 1 : 0;
bool f2 = Cross(Point(r1,c1) - Point(r2,c2),Point(x,y) - Point(r2,c2)) > 0 ? 1 : 0;
if (f1 ^ f2) swap(r1,r2),swap(c1,c2);
L[++tot] = Line(Point(r2,c2),Point(r1,c1) - Point(r2,c2));
}
DB Calc(Point *p,int N)
{
DB ret = 0; p[N] = p[0];
for (int i = 0; i < N; i++)
ret += Cross(p[i],p[i+1]);
return fabs(ret) / 2.00;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n;
for (int i = 0; i < n; i++)
{
DB x,y; scanf("%lf%lf",&x,&y);
D[i] = Point(x,y);
}
DB a = D[0].y - D[1].y,b = D[1].x - D[0].x;
D[n] = D[0]; DB c = Cross(D[0],D[1]);
for (int i = 1; i < n; i++)
{
DB A = D[i].y - D[i+1].y,B = D[i+1].x - D[i].x;
DB C = Cross(D[i],D[i+1]); A = A - a; B = B - b; C = C - c;
Insert(-A,-B,-C);
/*Point p = fabs(B) > EPS ? Point(0.00,-C / B) : Point(-C / A,0.00);
L[++tot] = Line(p,Point(B,-A));*/
}
L[++tot] = Line(D[0],D[1] - D[0]);
sort(L + 1,L + tot + 1); s[head = tail = 1] = L[1];
for (int i = 2; i <= tot; i++)
{
while (head < tail && !OnLeft(sec[tail-1],L[i])) --tail;
while (head < tail && !OnLeft(sec[head],L[i])) ++head;
s[++tail] = L[i];
if (fabs(Cross(s[tail].v,s[tail-1].v)) <= EPS)
{--tail; if (OnLeft(L[i].p,s[tail])) s[tail] = L[i];}
if (head < tail) sec[tail-1] = GetIntersection(s[tail],s[tail-1]);
}
while (head < tail && !OnLeft(sec[tail-1],s[head])) --tail;
sec[tail] = GetIntersection(s[tail],s[head]); tot = 0;
for (int i = head; i <= tail; i++) sec[tot++] = sec[i];
printf("%.4lf\n",Calc(sec,tot) / Calc(D,n));
return 0;
}