4445: [Scoi2015]小凸想跑步

4445: [Scoi2015]小凸想跑步

Time Limit: 2 Sec   Memory Limit: 128 MB
Submit: 415   Solved: 140
[ Submit][ Status][ Discuss]

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


Source

[ Submit][ Status][ Discuss]



设小凸站的位置的坐标为(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;
}

你可能感兴趣的:(半平面交)