24h購物| | PChome| 登入
2013-09-23 09:25:14| 人氣1,817| 回應0 | 上一篇 | 下一篇

[UVA][半平面交&射線法] 588 - Video Surveillance

推薦 0 收藏 0 轉貼0 訂閱站台


  Video Surveillance 

A friend of yours has taken the job of security officer at the Star-Buy Company, a famous depart- ment store. One of his tasks is to install a video surveillance system to guarantee the security of the customers (and the security of the merchandise of course) on all of the store's countless floors. As the company has only a limited budget, there will be only one camera on every floor. But these cameras may turn around to look in every direction.


The first problem is to choose where to install the camera for every floor. The only requirement is that every part of the room must be visible from there. In the following figure the left floor can be completely surveyed from the position indicated by a dot, while for the right floor, there is no such position, the given position failing to see the lower left part of the floor.

Before trying to install the cameras, your friend first wants to know whether there is indeed a suitable position for them. He therefore asks you to write a program that, given a ground plan, de- termines whether there is a position from which the whole floor is visible. All floor ground plans form rectangular polygons, whose edges do not intersect each other and touch each other only at the corners.

Input 

The input file contains several floor descriptions. Every description starts with the number n of vertices that bound the floor ( $4 leŸ n leŸ 100$). The next n lines contain two integers each, the x and y coordinates for the n vertices, given in clockwise order. All vertices will be distinct and at corners of the polygon. Thus the edges alternate between horizontal and vertical.

A zero value for n indicates the end of the input.

Output 

For every test case first output a line with the number of the floor, as shown in the sample output. Then print a line stating ``Surveillance is possible.'' if there exists a position from which the entire floor can be observed, or print ``Surveillance is impossible.'' if there is no such position.

Print a blank line after each test case.

Sample Input 

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
0

Sample Output 

Floor #1
Surveillance is possible.

Floor #2
Surveillance is impossible.



Miguel A. Revilla
1998-03-10


題目描述:

詢問一個簡單多邊形是否存在可以放置一個監視器看到所有角落,
也就是問多邊形存不存在一個"核"。

題目解法:


凸多邊形不用講一定存在核!而簡單多邊形要判斷的話,
考慮看到一條牆壁,則可行解一定在其延長的其中一邊,對於所有牆壁查找交集可能。


中間一定會用"半平面"去處理切割交集,現在的問題是,如何決策要取哪一邊?

網路上提供了找凸凹什麼的做法,我看不是很懂。

題目給定的方式是順時針,因此決策哪一邊的時候,會拉兩點成為一直線去切半平面,

而對於下一個鄰近點時,這三個點會有一個三角形,查找邊上中間那個點有沒有在簡單多邊形中,

如果在的話,則選同一邊進行取捨。

因此判斷一個點有沒有在簡單多邊形內部時,使用射線法進行判斷。

半平面的做法只寫一個樸素的,沒有快速的 O(nlogn)。

特別注意到,題目問的是存不存在一個核,並不能用半平面的面積進去判斷。

即使解是一個點也算答案,判斷集合是否非空。


#include <stdio.h>
#include <math.h>
#include <algorithm>
#define DEBUG 0
using namespace std;
struct Pt {
    double x, y;
    Pt(double a=0, double b=0):
        x(a), y(b) {}
    bool operator !=(const Pt &a) const {
        return fabs(x-a.x) > 1e-6 || fabs(y-a.y) > 1e-6;
    }
    bool operator ==(const Pt &a) const {
        return fabs(x-a.x) < 1e-6 && fabs(y-a.y) < 1e-6;
    }
};
struct Polygon {
    Pt p[256];// clockwise
    int n;
};
int inPolygon(Polygon p, Pt q) {
    int i, j, cnt = 0;
    for(i = 0, j = p.n-1; i < p.n; j = i++) {
        if(p.p[i].y > q.y != p.p[j].y > q.y &&
           q.x < (p.p[j].x-p.p[i].x)*(q.y-p.p[i].y)/(p.p[j].y-p.p[i].y)+p.p[i].x)
           cnt++;
    }
    return cnt&1;
}
Polygon cutPolygon(double side, Polygon &p, Pt p1, Pt p2) {
    // side : < 0 left, > 0 right, cut by lines(a, b)
    int i, j, k;
    double a, b, c;//ax + by + c = 0, pass {p1, p2}
    Polygon A, B;// divide two or one set.
    Pt intersection[2];// polygon divide by lines.
    int cnt = 0;
    a = p1.y - p2.y, b = p2.x - p1.x;
    if(a < 0)    a = -a, b = -b;
    c = -(a*p1.x+b*p1.y);   
    p.p[p.n] = p.p[0];
    A.n = B.n = 0;
    for(i = 0; i < p.n; i++) {
        if(cnt == 1) {
            if(B.n == 0 || B.p[B.n-1] != p.p[i])
                B.p[B.n++] = p.p[i];
        } else {
            if(A.n == 0 || A.p[A.n-1] != p.p[i])
                A.p[A.n++] = p.p[i];
        }
        // segment&lines intersecion
        if((a*p.p[i].x+b*p.p[i].y+c)*(a*p.p[i+1].x+b*p.p[i+1].y+c) < 1e-6) {
            if(cnt == 2)    continue;
            double ta, tb, tc;
            ta = p.p[i].y - p.p[i+1].y, tb = p.p[i+1].x - p.p[i].x;
            tc = -(ta*p.p[i].x+tb*p.p[i].y);
            double d, dx, dy;
            d = a*tb-b*ta;
            dx = (-c)*tb-b*(-tc), dy = a*(-tc)-(-c)*ta;
            if(fabs(d) < 1e-6) {
                continue;
                //dx = p.p[i].x, dy = p.p[i].y;
            } else {
                dx /= d, dy /= d;
            }
            if(cnt == 1 && intersection[0] == Pt(dx, dy))
                continue;
            intersection[cnt++] = Pt(dx, dy);
            if(A.n == 0 || A.p[A.n-1] != Pt(dx, dy))
                A.p[A.n++] = Pt(dx, dy);
            if(B.n == 0 || B.p[B.n-1] != Pt(dx, dy))
                B.p[B.n++] = Pt(dx, dy);
        }
    }           
    while(A.n > 1 && A.p[0] == A.p[A.n-1])
        A.n--;   
    while(B.n > 1 && B.p[0] == B.p[B.n-1])
        B.n--;
#if DEBUG == 1
    printf("%d %lf %lf\n", cnt, intersection[0].x, intersection[0].y);
    puts("A -----");
    for(i = 0; i < A.n; i++)
        printf("(%lf %lf)\n", A.p[i].x, A.p[i].y);
       
    puts("B -----");
    for(i = 0; i < B.n; i++)
        printf("(%lf %lf)\n", B.p[i].x, B.p[i].y);
#endif
    if(A.n >= 2) {
        double f;
        for(i = 0; i < A.n; i++) {
            f = a*A.p[i].x+b*A.p[i].y+c;
            if(fabs(f) > 1e-6)
                break;
        }
        if(i == A.n)    return B;
        //printf("fa %lf\n", f);
        if((f < 0) == (side < 0))
            return A;
        else
            return B;
    } else {       
        double f;
        for(i = 0; i < B.n; i++) {
            f = a*B.p[i].x+b*B.p[i].y+c;
            if(fabs(f) > 1e-6)
                break;
        }
        if(i == B.n)    return A;
        //printf("fb %lf\n", f);
        if((f < 0) == (side < 0))
            return B;
        else
            return A;
    }
}
int main() {  
    //freopen("video.in","r+t",stdin);
    //freopen("out.txt","w+t",stdout);
    int cases = 0;
    int i, j, k;
    Polygon in;
    Polygon solution;
    while(scanf("%d", &in.n) == 1 && in.n) {
        for(i = 0; i < in.n; i++)// clockwise
            scanf("%lf %lf", &in.p[i].x, &in.p[i].y);
        solution.n = 4;
        double lx, ly, rx, ry;
        lx = rx = in.p[0].x;
        ly = ry = in.p[0].y;
        for(i = 0; i < in.n; i++) {
            lx = min(lx, in.p[i].x);
            ly = min(ly, in.p[i].y);
            rx = max(rx, in.p[i].x);
            ry = max(ry, in.p[i].y);
        }
        solution.p[0] = Pt(lx, ry);//left upper
        solution.p[1] = Pt(rx, ry);//right upper
        solution.p[2] = Pt(rx, ly);//right bottom
        solution.p[3] = Pt(lx, ly);//left bottom
        // solve
        for(i = 0; i < in.n; i++) {// for each wall.
            Pt p1 = in.p[i], p2 = in.p[(i+1)%in.n], p3 = in.p[(i+2)%in.n];
            Pt mp = Pt((p1.x+p3.x)/2.0, (p1.y+p3.y)/2.0);
            //printf("%lf %lf\n", mp.x, mp.y);
            double a, b, c;//ax + by + c = 0, pass {p1, p2}
            a = p1.y - p2.y, b = p2.x - p1.x;
            if(a < 0)    a = -a, b = -b;
            c = -(a*p1.x+b*p1.y);
            double side = a*mp.x+b*mp.y+c;
            if(a*mp.x+b*mp.y+c < 0) {//left side
                if(inPolygon(in, mp))    side = -1;
                else                    side = 1;
            } else {
                if(inPolygon(in, mp))    side = 1;
                else                    side = -1;
            }
            solution = cutPolygon(side, solution, p1, p2);           
            while(solution.n > 1 && solution.p[0] == solution.p[solution.n-1])
                solution.n--;
            if(solution.n == 0)    break;
#if DEBUG == 1
            printf("%lf x + %lf y + %lf = 0\n", a, b, c);
            printf("%d- side %lf %lf %lf\n", solution.n, side, mp.x, mp.y);
            for(j = 0; j < solution.n; j++)
                printf("%lf %lf\n", solution.p[j].x, solution.p[j].y);
            printf("########################### %d\n", i);
            getchar();
#endif
        }
        printf("Floor #%d\n", ++cases);
        printf("Surveillance is %spossible.\n", solution.n ? "" : "im");
        puts("");
        //printf("%d\n", solution.n);
    }
    return 0;
}
/*
20
0 0
0 -1
-1 -1
-1 1
2 1
2 -3
-3 -3
-3 3
4 3
4 -5
-5 -5
-5 3
-4 3
-4 -4
3 -4
3 2
-2 2
-2 -2
1 -2
1 0
*/

台長: Morris
人氣(1,817) | 回應(0)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 教育學習(進修、留學、學術研究、教育概況) | 個人分類: UVA |
此分類下一篇:[UVA][maxflow] 1242 - Necklace
此分類上一篇:[UVA][大整數因數分解] 11476 - Factorizing Larget Integers

是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文