[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

Solution

比较麻烦的一道题。
根据叉积的公式,可以知道,点 ( x , y ) ( X i , Y i ) ( X j , Y j ) ( x , y ) 在凸多边形内,且 j = ( i + 1 ) mod n )构成的三角形面积为:

( X i x ) ( Y j y ) ( X j x ) ( Y i y )

展开式子得到:
X i Y j X i y Y j x X j Y i + X j y + Y i x

而题意就是要求站位 ( x , y ) 对于每个 i [ 1 , n 1 ] , j = ( i + 1 ) mod n ,都有:
X 0 Y 1 X 0 y Y 1 x X 1 Y 0 + X 1 y + Y 0 x X i Y j X i y Y j x X j Y i + X j y + Y i x

实际上就是半平面:
( Y j Y i + Y 0 Y 1 ) x + ( X i X j + X 1 X 0 ) y

+ ( X 0 Y 1 X 1 Y 0 + X j Y i X i Y j ) 0

一共有 n 1 个限制。
再附加一个: ( x , y ) 必须在向量 ( X 0 , Y 0 ) ( X 1 , Y 1 ) 的左侧,这样就保证了 ( 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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/80033526