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;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
11-21 17:16
科大讯飞 算法工程师 28.0k*14.0, 百分之三十是绩效,惯例只发0.9
点赞 评论 收藏
分享
某牛奶:一觉醒来全球程序员能力下降200%,小伙成功scanf惊呆在座个人。
点赞 评论 收藏
分享
11-24 11:23
门头沟学院 C++
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务