1. 程式人生 > >[CQOI2006]凸多邊形

[CQOI2006]凸多邊形

一年前寫的程式碼現在已經慘不忍睹了,趁著 olinr講計算幾何,再打一遍板子。

半平面交的步驟是:

  1. 將所有半平面極角排序

  2. 維護一個雙端佇列,按照極角序更新首尾的半平面,然後插入半平面

  3. 最後再將首尾更新一次

最後佇列裡所有的半平面即為答案。

下面是重寫後的程式碼,感覺好看多了~

#include <bits/stdc++.h>
using namespace std;

const double eps  = 1e-6;

struct Vector
{
    double x, y;
    Vector(double x = 0, double y = 0) : x(x), y(y) {}
    double mod() {return sqrt(x * x + y * y);}
};

struct Line
{
    Vector p, v;
}a[510];

int n, nn;

Vector operator+(const Vector &a, const Vector &b) {return Vector(a.x + b.x, a.y + b.y);}
Vector operator-(const Vector &a, const Vector &b) {return Vector(a.x - b.x, a.y - b.y);}
Vector operator*(const Vector &a, const double &b) {return Vector(a.x * b, a.y * b);}
Vector operator/(const Vector &a, const double &b) {return Vector(a.x / b, a.y / b);}
Vector operator*(const double &a, const Vector &b) {return Vector(a * b.x, a * b.y);}
double operator*(const Vector &a, const Vector &b) {return a.x * b.x + a.y * b.y;}
double operator^(const Vector &a, const Vector &b) {return a.x * b.y - a.y * b.x;}

bool polar_cmp(const Line &a, const Line &b)
{
    if (fabs(atan2(a.v.y, a.v.x) - atan2(b.v.y, b.v.x)) > eps)
        return atan2(a.v.y, a.v.x) < atan2(b.v.y, b.v.x);
    return (a.v ^ (b.p - a.p)) < 0;
}

Vector inter(const Line &a, const Line &b)
{
    return b.p + b.v * (((b.p - a.p) ^ a.v) / (a.v ^ b.v));
}

void input_poly()
{
    int m, x[55], y[55];
    scanf("%d", &m);
    for (int i = 1; i <= m; i++)
        scanf("%d%d", &x[i], &y[i]);
    x[m + 1] = x[1], y[m + 1] = y[1];
    for (int i = 1; i <= m; i++)
        a[++nn].p = Vector(x[i], y[i]), a[nn].v = Vector(x[i + 1] - x[i], y[i + 1] - y[i]);
}

Line q[2333];
Vector li[2333];
int top, bottom;

bool valid(const Vector p, const Line &l)
{
    return (l.v ^ (p - l.p)) > 0;
}

void insert(const Line &l)
{
    while (top - bottom >= 2 && valid(inter(q[top], q[top - 1]), l) == false)
        top--;
    while (top - bottom >= 2 && valid(inter(q[bottom + 1], q[bottom + 2]), l) == false)
        bottom++;
    q[++top] = l;
}

int main()
{
    int fuck;
    scanf("%d", &fuck);
    for (int i = 1; i <= fuck; i++)
        input_poly();
    sort(a + 1, a + 1 + nn, polar_cmp);
    for (int i = 1; i <= nn; i++)
        if (i == 1 || fabs(atan2(a[i].v.y, a[i].v.x) - atan2(a[i - 1].v.y, a[i - 1].v.x)) > eps)
            a[++n] = a[i];
    for (int i = 1; i <= n; i++)
        insert(a[i]);
    while (top - bottom >= 2 && valid(inter(q[top], q[top - 1]), q[bottom + 1]) == false)
        top--;
    while (top - bottom >= 2 && valid(inter(q[bottom + 1], q[bottom + 2]), q[top]) == false)
        bottom++;
    q[bottom] = q[top];
    for (int i = bottom; i < top; i++)
        li[i] = inter(q[i], q[i + 1]);
    li[top] = li[bottom];
    double res = 0;
    for (int i = bottom; i < top; i++)
        res += (li[i] ^ li[i + 1]);
    printf("%.3f\n", res / 2);
    return 0;
}