1. 程式人生 > >POJ 3335 Rotating Scoreboard(半平面交)

POJ 3335 Rotating Scoreboard(半平面交)

Description:

This year, ACM/ICPC World finals will be held in a hall in form of a simple polygon. The coaches and spectators are seated along the edges of the polygon. We want to place a rotating scoreboard somewhere in the hall such that a spectator sitting anywhere on the boundary of the hall can view the scoreboard (i.e., his line of sight is not blocked by a wall). Note that if the line of sight of a spectator is tangent to the polygon boundary (either in a vertex or in an edge), he can still view the scoreboard. You may view spectator’s seats as points along the boundary of the simple polygon, and consider the scoreboard as a point as well. Your program is given the corners of the hall (the vertices of the polygon), and must check if there is a location for the scoreboard (a point inside the polygon) such that the scoreboard can be viewed from any point on the edges of the polygon.

Input:

The first number in the input line, T is the number of test cases. Each test case is specified on a single line of input in the form n x1 y1 x2 y2 … xn yn where n (3 ≤ n ≤ 100) is the number of vertices in the polygon, and the pair of integers xi yi sequence specify the vertices of the polygon sorted in order.

Output:

The output contains T lines, each corresponding to an input test case in that order. The output line contains either YES or NO depending on whether the scoreboard can be placed inside the hall conforming to the problem conditions.

Sample Input:

2 4 0 0 0 1 1 1 1 0 8 0 0 0 2 1 2 1 1 2 1 2 2 3 2 3 0

Sample Output:

YES NO

題目連結

判斷多邊形是否有核心。

半平面交直接用模板即可。

AC程式碼:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 1e2 + 5;
const double eps = 1e-8;

int Sgn(double X) {
    if (fabs(X) < eps) {
        return 0;
    }
    return X < 0 ? -1 : 1;
}

struct Point {
    double X, Y;

    Point() {}
    Point(double _X, double _Y) {
        X = _X;
        Y = _Y;
    }

    void Input() {
        scanf("%lf%lf", &X, &Y);
    }

    Point operator - (const Point &B) const {
        return Point(X - B.X, Y - B.Y);
    }

    double operator * (const Point &B) const {
        return X * B.X + Y * B.Y;
    }

    double operator ^ (const Point &B) const {
        return X * B.Y - Y * B.X;
    }
};

struct Segment {
    Point S, T;

    Segment() {}
    Segment(Point _S, Point _T) {
        S = _S;
        T = _T;
    }

    double operator ^ (const Segment &B) const {
        return (T - S) ^ (B.T - B.S);
    }
};

bool IsParallel(Segment A, Segment B) {
    return Sgn((A.T - A.S) ^ (B.T - B.S)) == 0;
}

Point IntersectionPoint(Segment A, Segment B) {
    double X = (B.T - B.S) ^ (A.S - B.S), Y = (B.T - B.S) ^ (A.T - B.S);
    return Point((A.S.X * Y - A.T.X * X) / (Y - X), (A.S.Y * Y - A.T.Y * X) / (Y - X));
}

// 半平面,表示S->T逆時針(左側)的半平面
struct HalfPlane:public Segment {
    double Angle;

    HalfPlane() {}
    HalfPlane(Point _S, Point _T) {
        S = _S;
        T = _T;
    }
    HalfPlane(Segment _ST) {
        S = _ST.S;
        T = _ST.T;
    }

    // 計算極角
    void CalAngle() {
        Angle = atan2(T.Y - S.Y, T.X - S.X);
    }
    
    // 極角排序
    bool operator < (const HalfPlane &B) const {
        return Angle < B.Angle;
    }
};

int T;
int N;
int Tot;
HalfPlane halfplanes[maxn];
Point points[maxn];
int Front, Tail;
int Que[maxn];

void Push(HalfPlane X) {
    halfplanes[Tot++] = X;
}

void Unique() {
    int Cnt = 1;
    for (int i = 1; i < Tot; ++i) {
        if (Sgn(halfplanes[i].Angle - halfplanes[i - 1].Angle) != 0) {
            halfplanes[Cnt++] = halfplanes[i];
        }
        else if (Sgn((halfplanes[Cnt - 1].T - halfplanes[Cnt - 1].S) ^ (halfplanes[i].S - halfplanes[Cnt - 1].S)) > 0) {
            halfplanes[Cnt - 1] = halfplanes[i];
        }
    }
    Tot = Cnt;
}

bool HalfPlaneInsert() {
    for (int i = 0; i < Tot; ++i) {
        halfplanes[i].CalAngle();
    }
    sort(halfplanes, halfplanes + Tot);
    Unique();
    Que[Front = 0] = 0;
    Que[Tail = 1] = 1;
    points[1] = IntersectionPoint(halfplanes[0], halfplanes[1]);
    for (int i = 2; i < Tot; ++i) {
        while (Front < Tail && Sgn((halfplanes[i].T - halfplanes[i].S) ^ (points[Tail] - halfplanes[i].S)) < 0) {
            Tail--;
        }
        while (Front < Tail && Sgn((halfplanes[i].T - halfplanes[i].S) ^ (points[Front + 1] - halfplanes[i].S)) < 0) {
            Front++;
        }
        Que[++Tail] = i;
        if (IsParallel(halfplanes[i], halfplanes[Que[Tail - 1]])) {
            return false;
        }
        points[Tail] = IntersectionPoint(halfplanes[i], halfplanes[Que[Tail - 1]]);
    }
    while (Front < Tail && Sgn((halfplanes[Que[Front]].T - halfplanes[Que[Front]].S) ^ (points[Tail] - halfplanes[Que[Front]].S)) < 0) {
        Tail--;
    }
    while (Front < Tail && Sgn((halfplanes[Que[Tail]].T - halfplanes[Que[Tail]].S) ^ (points[Front + 1] - halfplanes[Que[Tail]].S)) < 0) {
        Front++;
    }
    if (Front + 1 >= Tail) {
        return false;
    }
    return true;
}

int main(int argc, char *argv[]) {
    scanf("%d", &T);
    for (int Case = 1; Case <= T; ++Case) {
        Tot = 0;
        scanf("%d", &N);
        for (int i = 0; i < N; ++i) {
            points[i].Input();
        }
        reverse(points, points + N);
        for (int i = 0; i < N; ++i) {
            Push(HalfPlane(points[i], points[(i + 1) % N]));
        }
        if (HalfPlaneInsert()) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }
	return 0;
}