poj 1912 A highway and the seven dwarfs

A highway and the seven dwarfs

Time Limit: 8000MS   Memory Limit: 30000K
Total Submissions: 2622   Accepted: 535
Case Time Limit: 3000MS

Description

Once upon a time, there was a land where several families of dwarfs were living. This land was called Dwarfland. Each family lived in one house. Dwarfs were often visiting their friends from the other families. Because the Dwarfland was free of evil, it happened that each dwarf visited each other during some short period of time.

Once, the humans living in countries around Dwarfland decided to build several straight highways. As the humans weren‘t aware of the dwarfs, some of the planned highways passed through Dwarfland. The dwarfs discovered this and were quite unhappy about it. The dwarfs are very little, and also very slow, so they are unable to cross the highway safely.

The dwarfs managed to get the plans for the highways somehow, and now they need your help. They would like to keep on visiting each other, so they don‘t like those highways which divide their houses into two non-empty parts. After they find out which highways they don‘t like, they will magically prevent the humans from building them.

The dwarfs are very little, and cannot reach the keyboard. So they asked for your help.

Task 

Given is a number N of points (houses) in the plane and several straight lines (highways). For each given line, your task is to determine whether all N points lie on the same side of the line or not. Your program has to output the answer for the currently processed line before reading the description of the next one. You may assume that no highway passes through any of the houses.

Input

Your program is supposed to read the input from the standard input and write its output to the standard output. The first line of the input contains one integer N ( 0 < = N < = 100 000). N lines follow, the i-th of them contains two real numbers xi, yi ( -109 < = xi, yi < = 109) separated by a single space - the coordinates of the i-th house.

Each of the following lines contains four real numbers X1, Y1, X2, Y2 ( -109 < = X1, Y1, X2, Y2 < = 109) separated by a single space. These numbers are the coordinates of two different points [X1, Y1] and [X2, Y2], lying on the highway.

Output

For each line of input, your program is supposed to output a line containing the string "GOOD" if all of the given points are on the same side of the given line, or "BAD" if the given line divides the points.

Sample Input

4
0.0 0
6.00 -0.001
3.125 4.747
4.747 0.47
5 3 7 0
4 -4.7 7 4.7
4 47 4 94

Sample Output

GOOD
BAD
BAD

Hint

Huge input,scanf is recommended. 

题意:给定平面上几个点的坐标,再给出一条直线,判断这条直线是不是能把点分离成两部分

思路:先找平面上这些点的凸包,那么要是凸包和直线相交,则直线肯定可以把点分离成两部分,问题的关键在于判断直线是否和凸包相交。

可以将凸包的每条边以及直线都考虑成向量的形式,那么凸包的边所形成的向量在极坐标系下的极角大小变化一定是单调的,可以看下图:

      

第一幅图中,向量AE,ED,DC,CB,BA的极角在 坐标系中变化是单调的,于是把他们都移到图二中来,都以O点为起点,按照极角大小排序并编号,凸包的算法因人而异,我现在用的凸包算法是以最左端的A点开始存储,并按照逆时针方向存储点的,那么AE向量最好标记为极角最小的向量,ED次之,以此类推,那么我们就得设定极角的变化范围为(-90,270],这样将所有的向量排好序,并标记好编号,譬如右图的1向量代表AE向量。。。现在又给出一条直线L1,如何得知L1和凸包相交呢?我们平移L1的向量形式,移到L1只割掉了凸包一个点的位置(一共两个位置),L2的方向为p1p2,L3的方向为p2p1,我们发现这两条向量如果都要逆时针转一个方向,分别转动到向量DC和向量BA的位置需要转动的角度是最小的,而向量DC和BA的端点D,B又恰恰是向量L3和L1所割掉的点那么如果线段DB和直线L1有交点,则L1一定和凸包存在交点的。这个规律放到图二来看,直线L的向量形式为p2p1,转到向量3是所转角度最小的,其反向的向量转到向量5转角度又是最小的,向量3与向量5都是可以通过二分查找找出来,找到向量之后在取其起始端点,判断这两个起始端点是否与直线相交。

AC代码:

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cstring>
#include<string>
#include<functional>
#include<cmath>
#include<stack>
using namespace std;
const int N_MAX = 100000 + 5;
#define INF 0x3f3f3f3f
#define EPS 1e-10
#define equals(a,b) (fabs(a-b)<EPS)
#define pi acos(-1.0)
#define BOTTOM 0
#define LEFT 1
#define RIGHT 2
#define TOP 3

static const int COUNTER_CLOCKWISE = -1;
static const int CLOCKWISE = 1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

double add(double a,double b) {
    if (abs(a + b) < EPS*(abs(a) + abs(b)))return 0;
    return a + b;
}

class point {
public:
    double x, y;
    point(double x = 0, double y = 0) :x(x), y(y) {}
    point operator +(point p) { return point(x+p.x, y+p.y); }
    point operator -(point p) { return point(x - p.x,y - p.y); }
    point operator *(double a) { return point(a*x, a*y); }
    point operator /(double a) { return point(x / a, y / a); }
    double norm() { return x*x + y*y; }
    double abs() { return sqrt(norm()); }
    bool operator<(const point&p)const {
        return x != p.x ? x < p.x : y < p.y;
    }
    bool operator ==(const point&p)const {
        return x == p.x && y == p.y;
    }
    double dot(point p) {
        return x*p.x+y*p.y;
    }
    double det(point p) {
        return x*p.y- y*p.x;
    }
};

struct Segment {
    point p1, p2;
    Segment(point p1 = point(), point p2 = point()) :p1(p1), p2(p2) {}
};
typedef Segment line;

typedef vector<point>Polygon;
//????????????p0p1?????????p0p2???????????????
int ccw(point p0, point p1, point p2) {
    point a = p1 - p0;
    point b = p2 - p0;
    if (a.det(b) > EPS)return COUNTER_CLOCKWISE;
    if (a.det(b) < -EPS)return CLOCKWISE;
    if (a.dot(b) < -EPS)return ONLINE_BACK;
    if (a.norm() >= b.norm())return ON_SEGMENT;//!!
    return ONLINE_FRONT;
}
//????????????p1p2???p3p4????????????
bool intersect(point p1, point p2, point p3, point p4) {
    return (ccw(p1, p2, p3)*ccw(p1, p2, p4) < 0 &&
        ccw(p3, p4, p1)*ccw(p3, p4, p2) < 0);//!!!!!!!!!!!!!!!!!!!!!!!!!!!
}

inline double normalize(double r)
{
    if (r < -pi / 2.0 + EPS) r += pi * 2;
    return r;
}

double arg(const point& p) { return normalize(atan2(p.y, p.x)); }
inline bool double_cmp(double a,double b) {
    return a + EPS < b;
}

////
typedef vector<point>Polygon;

vector<point> convex_hull(point *ps, int N)
{
    sort(ps, ps + N);
    int k = 0;   // 凸包的顶点数
    vector<point> qs(N * 2);   // 构造中的凸包
                           // 构造凸包的下侧
    for (int i = 0; i < N; ++i)
    {
        while (k > 1 && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k;
        qs[k++] = ps[i];
    }
    // 构造凸包的上侧
    for (int i = N - 2, t = k; i >= 0; --i)
    {
        while (k > t && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) --k;
        qs[k++] = ps[i];
    }
    qs.resize(k - 1);
    return qs;
}

point s[N_MAX];
int n;
double a[N_MAX];//记录凸包每条边行成的向量倾斜度
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%lf%lf", &s[i].x, &s[i].y);
    }
    int N;
    Polygon con;
    if (n > 1) { 

         con=convex_hull(s,n);
        N = con.size();
        con.push_back(con[0]);
    }
        for (int i = 0; i <N; i++) {
            a[i] = arg(con[i + 1] - con[i]);
        }

    sort(a, a + N, double_cmp);
    point p1, p2;
    while (scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y)!=EOF) {
        if (n < 2) { puts("GOOD"); continue; }
        int i = upper_bound(a, a + N, arg(p2 - p1), double_cmp) - a;
        int j = upper_bound(a, a + N, arg(p1 - p2), double_cmp) - a;
        puts((((p2 - p1).det(con[i] - p1) * (p2 - p1).det(con[j] - p1) > -EPS)) ? "GOOD" : "BAD");

    }

    return 0;
}

时间: 2024-10-24 00:32:54

poj 1912 A highway and the seven dwarfs的相关文章

POJ 1912 A highway and the seven dwarfs (凸包)

[题目链接] http://poj.org/problem?id=1912 [题目大意] 给出一些点,表示一些屋子,这些屋子共同组成了村庄,现在要建一些高速公路 问是否经过了村庄. [题解] 这些屋子的关键点一定在凸包上,所以我们只要求出凸包,判断是否和线相交即可 我们求出与高速公路相近和近似相反的向量,判断连线是否与这条公路相交即可. [代码] #include <cstdio> #include <algorithm> #include <cmath> #inclu

POJ1912 A highway and the seven dwarfs (判断凸包与直线相交 logn)

POJ1912 给定n个点 和若干条直线,判断对于一条直线,是否存在两个点在直线的两侧. 显然原命题等价于 凸包与直线是否相交. O(n)的算法是显而易见的 但是直线数量太多 就会复杂到O(n^2)由于n<=100000 会TLE 凸包有个很好的性质,我们没有利用, 那就是凸包的边相对于要判断的直线是极角有序的! 于是得到算法: 构造好凸包后,二分找凸包上第一个与正向直线夹角大于0的线段和第一个与反向直线夹角大于0的线段 然后判断两线段的起点是否在直线两侧即可. 代码实现有一点注意的细节:不要用

挑战程序设计竞赛 3.6 与平面和空间打交道的计算几何

POJ 1981:Circle and Points /* 题目大意:给出平面上一些点,问一个半径为1的圆最多可以覆盖几个点 题解:我们对于每个点画半径为1的圆,那么在两圆交弧上的点所画的圆,一定可以覆盖这两个点 我们对于每个点计算出其和其它点的交弧,对这些交弧计算起末位置对于圆心的极角, 对这些我们进行扫描线操作,统计最大交集数量就是答案. */ #include <cstdio> #include <algorithm> #include <cmath> #incl

[ACM] POJ 3485 Highway (区间选点问题)

Highway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 871   Accepted: 402 Description Bob is a skilled engineer. He must design a highway that crosses a region with few villages. Since this region is quite unpopulated, he wants to mini

POJ 3449 Geometric Shapes --计算几何,线段相交

题意: 给一些多边形或线段,输出与每一个多边形或线段的有哪一些多边形或线段. 解法: 想法不难,直接暴力将所有的图形处理成线段,然后暴力枚举,相交就加入其vector就行了.主要是代码有点麻烦,一步一步来吧. 还有收集了一个线段旋转的函数. Vector Rotate(Point P,Vector A,double rad){ //以P为基准点把向量A旋转rad return Vector(P.x+A.x*cos(rad)-A.y*sin(rad),P.y+A.x*sin(rad)+A.y*co

POJ 1160 Post Office

N个数到一个数的距离和最小,这个数一定是他们的中位数. dp[i][j]=前i个点,j个office的距离. dp[i][j]=min(dp[k-1][j-1]+w[k][i])    w[k][i]是k..i 修一个office的距离. Post Office Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 15687   Accepted: 8503 Description There is a straight hi

[2016-01-27][POJ][1751][B - Highways]

[2016-01-27][POJ][1751][B - Highways] B - Highways Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1751 Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a

POJ 2152 Fire

Fire Time Limit: 2000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 215264-bit integer IO format: %lld      Java class name: Main Country Z has N cities, which are numbered from 1 to N. Cities are connected by highways, and

POJ 1751 Highways (Kruskal 最小生成树)

Highways Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9654   Accepted: 2725   Special Judge Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia has a very poor system of public highways. The Flatopian