2013-04-11 20:43:07Morris

[UVA][幾何、半平面交] 11265 - The Sultan's Problem

Problem F
The Sultan’s Problem
Input: Standard Input

Output: Standard Output

 

Once upon a time, there lived a greatsultan, who was very much fond of his wife. He wanted to build a Tajmahal for his wife (ya, oursultan idolized Mughal emperor Shahjahan).But alas, due to budget cuts, loans, dues and many manythings, he had no fund to build something so big. So, he decided to build abeautiful garden, inside his palace.

 

The garden is a rectangular pieceof land. All the palace’s water lines run through the garden, thus, dividing itinto pieces of varying shapes. He wanted to cover each piece of the land withflowers of same kind.

Figure 1

The figure above shows a sampleflower garden. All the lines are straight lines, with two end points on twodifferent edge of the rectangle. Each piece of the garden is covered with thesame kind of flowers.

 

The garden has a small fountain,located at position (x,y).You can assume that, it is not on any of the lines. He wants to fill that piecewith her favourite flower. So, he asks you to findthe area of that piece.

 

Input

 

Input contains around 500 testcases. Each case starts with 5 integers, N, W, H, x,y, the number of lines, width and height of the garden and the locationof the fountain. Next N lines each contain 4 integers, x1y1 x2 y2, the two end points of the line.The end points are always on the boundary of the garden. You can assume that,the fountain is not located on any line.

Output

 

For each test case, output thecase number, with the area of the piece covered with her favouriteflower. Print 3 digits after the decimal point.

 

Constraints

  • 1 ≤ W, H ≤ 200,000
  • 1 ≤ N ≤ 500

 

Sample Input

Sample Output

3 100 100 20 30

0 0 100 100

100 0 0 100

0 40 40 100

 

Case #1: 1780.000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Problemsetter: Manzurur Rahman Khan

Special Thanks To: Mohammad MahmudurRahman



解題思路:

一個型態 polygon,以及求一條長直線交多邊形的兩交點,
如果有交的話,將這個多邊形一分為二,同時只保留涵蓋花園的那塊多邊形,
最後使用行列式算花園面積



#include <stdio.h>
#include <math.h>
struct Pt {
    double x, y;
};
struct Polygon {
    Pt p[505];
    int n;
};
double calcArea(Polygon &p) {
    static int i;
    double sum = 0;
    p.p[p.n] = p.p[0];
    for(i = 0; i < p.n; i++)
        sum += p.p[i].x*p.p[i+1].y - p.p[i].y*p.p[i+1].x;
    return fabs(sum/2);
}
void print(Polygon &p) {
    for(int i = 0; i < p.n; i++)
        printf("%lf %lf\n", p.p[i].x, p.p[i].y);
    puts("=====");
}
int main() {
    int n, w, h;
    int cases = 0;
    int i, j, k;
    double sx, sy, ex, ey, xi, yi;
    while(scanf("%d %d %d", &n, &w, &h) == 3) {
        scanf("%lf %lf", &xi, &yi);
        Polygon A, B, C;
        A.n = 4;
        A.p[0].x = 0, A.p[0].y = 0;
        A.p[1].x = w, A.p[1].y = 0;
        A.p[2].x = w, A.p[2].y = h;
        A.p[3].x = 0, A.p[3].y = h;
        while(n--) {
            scanf("%lf %lf %lf %lf", &sx, &sy, &ex, &ey);
            // ax + by + c = 0
            double a, b, c;
#define eps 1e-8
            double m = (sy-ey)/(sx-ex);
            if(fabs(sx-ex) < eps)
                a = 1, b = 0, c = -sx;
            else
                a = m, b = -1, c = -(sx*a+b*sy);
            //printf("%lf x + %lf y + %lf = 0\n", a, b, c);
            A.p[A.n] = A.p[0];
            B.n = 0, C.n = 0;
            Pt intP[2];
            int point = 0;
            for(i = 0; i < A.n; i++) {
                if(point == 1) {
                    if(B.n == 0 || fabs(B.p[B.n-1].x-A.p[i].x) > eps ||
                       fabs(B.p[B.n-1].y-A.p[i].y) > eps)
                    B.p[B.n++] = A.p[i];
                } else {
                    if(C.n == 0 || fabs(C.p[C.n-1].x-A.p[i].x) > eps ||
                       fabs(C.p[C.n-1].y-A.p[i].y) > eps)
                    C.p[C.n++] = A.p[i];
                }
                //printf("(%lf %lf)-(%lf %lf)\n", A.p[i].x, A.p[i].y, A.p[i+1].x, A.p[i+1].y);
                if((a*A.p[i].x+b*A.p[i].y+c)*(a*A.p[i+1].x+b*A.p[i+1].y+c) <= eps) {
                    if(point == 2)  continue;
                    double ta, tb, tc;
                    double tm = (A.p[i].y-A.p[i+1].y)/(A.p[i].x-A.p[i+1].x);
                    if(fabs(A.p[i].x-A.p[i+1].x) < eps)
                        ta = 1, tb = 0, tc = -A.p[i].x;
                    else
                        ta = tm, tb = -1, tc = -(A.p[i].x*ta+A.p[i].y*tb);
                    // ax+by+c = 0, ta*x+tb*y+tc = 0
                    //printf("%lf x + %lf y + %lf = 0\n", ta, tb, tc);
                    double rx, ry, r;
                    r = a*tb-ta*b;
                    rx = (-c)*tb-(-tc)*b;
                    ry = a*(-tc)-ta*(-c);
                    rx = rx/r;
                    ry = ry/r;
                    if(fabs(r) < eps)   continue; // no intersection
                    if(point == 1) {
                        if(fabs(rx-intP[0].x) < eps && fabs(ry-intP[0].y) < eps)
                            continue;
                    }
                    //printf("intersection %lf %lf\n", rx, ry);
                    intP[point].x = rx, intP[point].y = ry;
                    if(B.n == 0 || fabs(B.p[B.n-1].x-rx) > eps || fabs(B.p[B.n-1].y-ry) > eps)
                        B.p[B.n++] = intP[point];
                    if(C.n == 0 || fabs(C.p[C.n-1].x-rx) > eps || fabs(C.p[C.n-1].y-ry) > eps)
                        C.p[C.n++] = intP[point];
                    point++;
                }
            }
            if(point != 2)
                continue;
            int f1, f2;
            f1 = (a*B.p[B.n/2].x + b*B.p[B.n/2].y + c) < eps;
            f2 = (a*xi + b*yi + c) < eps;
            //print(B);
            //print(C);
            if(f1 == f2 && point) {// same side
                //puts("B side");
                A = B;
            } else {
                //puts("C side");
                A = C;
            }
            while(fabs(A.p[A.n-1].x-A.p[0].x) < eps &&
               fabs(A.p[A.n-1].y-A.p[0].y) < eps)
                A.n--;
            //print(A);
        }
        printf("Case #%d: %.3lf\n", ++cases, calcArea(A));
    }
    return 0;
}