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
Solution
比较麻烦的一道题。
根据叉积的公式,可以知道,点
(x,y)(Xi,Yi)(Xj,Yj)
(
x
,
y
)
(
X
i
,
Y
i
)
(
X
j
,
Y
j
)
(
(x,y)
(
x
,
y
)
在凸多边形内,且
j=(i+1)modn
j
=
(
i
+
1
)
mod
n
)构成的三角形面积为:
展开式子得到:
而题意就是要求站位 (x,y) ( x , y ) 对于每个 i∈[1,n−1],j=(i+1)modn i ∈ [ 1 , n − 1 ] , j = ( i + 1 ) mod n ,都有:
实际上就是半平面:
一共有 n−1 n − 1 个限制。
再附加一个: (x,y) ( x , y ) 必须在向量 (X0,Y0)(X1,Y1)→ ( X 0 , Y 0 ) ( X 1 , Y 1 ) → 的左侧,这样就保证了 (x,y) ( x , y ) 一定在多边形内。
这样,答案就是:
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5;
int n, tot, tot2;
struct cyx {
double x, y;
friend inline cyx operator + (cyx a, cyx b) {
return (cyx) {a.x + b.x, a.y + b.y};
}
friend inline cyx operator - (cyx a, cyx b) {
return (cyx) {b.x - a.x, b.y - a.y};
}
friend inline cyx operator * (cyx a, double b) {
return (cyx) {a.x * b, a.y * b};
}
friend inline cyx operator / (cyx a, double b) {
return (cyx) {a.x / b, a.y / b};
}
friend inline double operator * (cyx a, cyx b) {
return a.x * b.y - a.y * b.x;
}
} oz[N], otz[N];
struct pyz {cyx a, b; cyx o() {return a - b;}} b[N], a[N], Q[N];
double dist(cyx a, cyx b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
cyx orz(pyz x, pyz y) {
double s1 = (x.a - y.a) * (x.a - y.b), s2 = (x.b - y.b) * (x.b - y.a);
if (s1 + s2 == 0) return x.a; return x.a + x.o() * s1 / (s1 + s2);
}
bool check1(pyz x, pyz y) {
double tmp = x.o() * y.o();
return tmp > 0 || (tmp == 0 && y.o() * (y.a - x.a) > 0);
}
bool para(pyz x, pyz y) {return x.o() * y.o() == 0;}
bool comp(pyz x, pyz y) {
cyx p = x.o(), q = y.o(); if ((p.y < 0 || (p.y == 0 && p.x < 0))
&& (q.y > 0 || (q.y == 0 && q.x > 0))) return 1;
if ((p.y > 0 || (p.y == 0 && p.x > 0))
&& (q.y < 0 || (q.y == 0 && q.x < 0))) return 0; return check1(x, y);
}
bool check2(pyz a, pyz b, pyz x) {
cyx y = orz(a, b); return (x.a - y) * x.o() >= 0;
}
double solve() {
int i, H = 1, T = 2; sort(b + 1, b + n + 1, comp);
For (i, 1, n) if (i == 1 || !para(b[i], b[i - 1])) a[++tot] = b[i];
Q[1] = a[1]; Q[2] = a[2]; For (i, 3, tot) {
while (H < T && check2(Q[T - 1], Q[T], a[i])) T--;
while (H < T && check2(Q[H], Q[H + 1], a[i])) H++; Q[++T] = a[i];
}
while (H < T && check2(Q[T - 1], Q[T], Q[H])) T--;
For (i, H, T - 1) otz[++tot2] = orz(Q[i], Q[i + 1]);
otz[++tot2] = orz(Q[T], Q[H]); double ans = otz[1] * otz[tot2];
For (i, 1, tot2 - 1) ans += otz[i + 1] * otz[i]; return abs(ans);
}
int main() {
int i; n = read(); For (i, 1, n) oz[i].x = read(), oz[i].y = read();
double area = oz[1] * oz[n]; For (i, 1, n - 1) area += oz[i + 1] * oz[i];
area = abs(area); b[1] = (pyz) {oz[1], oz[2]}; For (i, 2, n) {
int j = i == n ? 1 : i + 1;
double A = oz[j].y - oz[i].y + oz[1].y - oz[2].y,
B = oz[i].x - oz[j].x - oz[1].x + oz[2].x,
C = oz[1].x * oz[2].y - oz[2].x * oz[1].y
+ oz[j].x * oz[i].y - oz[i].x * oz[j].y;
if (B != 0) {
A /= -B; C /= -B; cyx a = (cyx) {-i, -A * i + C},
k = (cyx) {i, A * i + C};
if (B > 0) b[i] = (pyz) {k, a}; else b[i] = (pyz) {a, k};
}
else {
C /= -A; cyx a = (cyx) {C, -i}, k = (cyx) {C, i + 1};
if (A > 0) b[i] = (pyz) {a, k}; else b[i] = (pyz) {k, a};
}
}
printf("%.4lf\n", solve() / area);
return 0;
}