1. 程式人生 > >POJ--2284--That Nice Euler Circuit【平面圖歐拉公式】

POJ--2284--That Nice Euler Circuit【平面圖歐拉公式】

time 說明 pop 求交點 content for pro main long long

鏈接:http://poj.org/problem?id=2284

題意:一個自己主動繪圖的機器在紙上(無限大)繪圖,筆尖從不離開紙,有n個指令,每一個指令是一個坐標,由於筆尖不離開紙,所以相鄰的坐標會連有一條直線,最後畫筆再回到起始點。

所以這個圖是一個連通圖,而且畫筆走過的路徑是一個歐拉回路。

如今問題來了。這個圖形將平面分成了幾部分。


思路:題目說明確一些就是告訴你一些幾何信息問平面被分成了幾部分。能夠用歐拉公式來做

歐拉公式:如果圖的頂點個數為n,邊數為m,區域數位r,則有 n - m + r = 2,前提必須是連通圖

知道隨意兩個就能求第三個


#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 90010
#define eps 1e-7
#define INF 0x3F3F3F3F      //0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 1313131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct Point{   //點
    double x, y;
    Point(double a = 0, double b = 0){
        x = a;
        y = b;
    }
};
struct LineSegment{ //線段
    Point s, e;
    LineSegment(Point a, Point b){
        s = a;
        e = b;
    }
};
struct Line{    //直線
    double a, b, c;
};
bool operator < (Point p1, Point p2){
    return (p1.x < p2.x || p1.x == p2.x) && p1.y < p2.y;
}
bool operator == (Point p1, Point p2){
    return fabs(p1.x - p2.x) < eps && fabs(p1.y - p2.y) < eps;
}
bool Online(LineSegment l, Point p){    //推斷點是否在線段上
    return fabs((l.e.x - l.s.x) * (p.y - l.s.y) - (p.x - l.s.x) * (l.e.y - l.s.y)) < eps
        && (p.x - l.s.x) * (p.x - l.e.x) < eps && (p.y - l.s.y) * (p.y - l.e.y) < eps;
}
Line MakeLine(Point p1, Point p2){  //將線段延長為直線
    Line l;
    if(p2.y > p1.y){
        l.a = p2.y - p1.y;
        l.b = p1.x - p2.x;
        l.c = p1.y * p2.x - p1.x * p2.y;
    }
    else{
        l.a = p1.y - p2.y;
        l.b = p2.x - p1.x;
        l.c = p1.x * p2.y - p1.y * p2.x;
    }
    return l;   //返回直線
}
bool LineIntersect(Line l1, Line l2, Point &p){ //推斷直線是否相交。並求出交點p
    double d = l1.a * l2.b - l2.a * l1.b;
    if(fabs(d) < eps) return false;
    //求交點
    p.x = (l2.c * l1.b - l1.c * l2.b) / d;
    p.y = (l2.a * l1.c - l1.a * l2.c) / d;
    return true;
}
bool LineSegmentIntersect(LineSegment l1, LineSegment l2, Point &p){    //推斷線段是否相交
    Line a, b;
    a = MakeLine(l1.s, l1.e), b = MakeLine(l2.s, l2.e); //將線段延長為直線
    if(LineIntersect(a, b, p))  //假設直線相交
        return Online(l1, p) && Online(l2, p);  //推斷直線交點是否在線段上,是則線段相交
    else
        return false;
}

bool cmp(Point a, Point b){
    if(fabs(a.x - b.x) < eps)   return a.y < b.y;
    else    return a.x < b.x;
}
Point p[MAXN], Intersection[MAXN];
int N, m, n;
int main(){
    int i, j, cas = 1;
    while(scanf("%d", &N), N){
        m = n = 0;
        for(i = 0; i < N; i++){
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        for(i = 0; i < N; i++){
            for(j = 0; j < N; j++){
                LineSegment l1(p[i], p[(i + 1) % N]), l2(p[j], p[(j + 1) % N]);
                Point p;
                if(LineSegmentIntersect(l1, l2, p))
                    Intersection[n++] = p;  //記錄交點
            }
        }
        sort(Intersection, Intersection + n, cmp);
        n = unique(Intersection, Intersection + n) - Intersection;
        for(i = 0; i < n; i++){
            for(j = 0; j < N; j++){
                LineSegment t(p[j], p[(j + 1) % N]);
                if(Online(t, Intersection[i]) && !(t.s == Intersection[i]))  //若有交點落在邊上,則該邊分裂成兩條邊
                    m++;
            }
        }
        printf("Case %d: There are %d pieces.\n", cas++, 2 - n + m);
    }
    return 0;
}


POJ--2284--That Nice Euler Circuit【平面圖歐拉公式】