Aizu 2448 Area Folding(复杂多边形求闭合面积并)

题意:给一个复杂多边形(可以自交),求闭合部分面积总和,一个点在闭合米部分的定义是,从它开始无论怎么走都无法不经过其他点到达无穷远处。

链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2448

解法:假设我们得到的简单多边形,那么直接用叉积可以求面积。现在如何将复杂的转化为简单的,只需求复杂边形的轮廓即可,方法是,先重建图,对于每个相邻点,建无向边,得到一个没有重边,没有重点,没有自环的简单图,然后,找到一个位置在最左下的点为起点p,再找到p出去的,向量角度值最小的边,以它为开始,求出这个图的轮廓即可。。注意,求出的轮廓终点也一定为p,这样子对于看上去不闭合的图,求出的多边形也闭合了,这样子不闭合的面积就会被算为0。。

#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
using namespace std;

const double eps = 1e-6, pi = acos(-1.0);
int sgn(double x){
    if(abs(x) < eps) return 0;
    else return x > 0 ? 1 : -1;
}

struct Point{
    double x, y;
    Point(){};
    Point(double x1, double y1){
        x = x1, y = y1;
    }
};
typedef Point Vector;
Vector operator + (Vector a, Vector b){
    return Vector(a.x + b.x, a.y + b.y);
}
Vector operator - (Vector a, Vector b){
    return Vector(a.x - b.x, a.y - b.y);
}
Vector operator * (Vector a, double b){
    return Vector(a.x * b, a.y * b);
}
double operator * (Vector a, Vector b){
    return a.x * b.x + a.y * b.y;
}
double operator % (Vector a, Vector b){
    return a.x * b.y - a.y * b.x;
}
bool operator == (Point a, Point b){
    return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
}

#define MAXN 100010
#define N 200
int n;
Point p[200], pv[MAXN];

struct Edge{
    int next, to;
}e[MAXN << 1];
int head[MAXN], ne, nv;
void add(int a, int b){
    int t = ++ne;
    e[t].to = b, e[t].next = head[a];
    head[a] = t;
}

bool inter(Point p1, Point p2, Point q1, Point q2){
    if(sgn((p1 - p2) % (q1 - q2)) == 0 ) return false;
    int t1 = sgn((p2 - p1) % (q1 - p1)) * sgn((p2 - p1) % (q2 - p1));
    int t2 = sgn((q2 - q1) % (p1 - q1)) * sgn((q2 - q1) % (p2 - q1));
    return t1 <= 0 && t2 <= 0;
}
Point getp(Point p1, Vector v1, Point p2, Vector v2){
    double t = ((p2 - p1) % v2) / (v1 % v2);
    return p1 + v1 * t;
}

vector<Point>seg[N], vp;

bool operator < (const Point a, const Point b){
    if(sgn(a.x - b.x) != 0) return sgn(a.x - b.x) < 0;
    else return sgn(a.y - b.y) < 0;
}
map<Point, int>mto;
set<pair<int,int> >se;
void build_edge(){
    for(int i = 0; i < n - 1; i++){
        seg[i].push_back(p[i]);
        seg[i].push_back(p[i + 1]);
        vp.push_back(p[i]);
        vp.push_back(p[i + 1]);
        for(int j = 0; j < n - 1; j++){
            if(inter(p[i], p[i+1], p[j], p[j+1]) == 0) continue;
            Point x = getp(p[i], p[i+1] - p[i], p[j], p[j+1] - p[j]);
            seg[i].push_back(x);
            vp.push_back(x);
        }
    }
    sort(vp.begin(), vp.end());
    nv = 0;
    for(int i = 0; i < vp.size(); i++){
        if(i > 0 && vp[i] == vp[i-1]) continue;
        mto[vp[i]] = ++nv;
        pv[nv] = vp[i];
    }

    for(int i = 1; i <= nv; i++) head[i] = -1;
    ne = 0;

    for(int i = 0; i < n - 1; i++){
        sort(seg[i].begin(), seg[i].end());
        for(int j = 1; j < seg[i].size(); j++){
            if(j > 0 && seg[i][j] == seg[i][j-1]) continue;
            int a = mto[seg[i][j]];
            int b = mto[seg[i][j-1]];
            if(a > b) swap(a, b);
            pair<int,int>pa = make_pair(a, b);
            if(se.find(pa) != se.end()) continue;
            se.insert(pa);
            add(a, b);
            add(b, a);
        }
    }
}

double angle(Vector v1, Vector v2){
    double a = atan2(v1.y, v1.x) - atan2(v2.y, v2.x);
    while(sgn(a) < 0) a += 2 * pi;
    while(sgn(a - 2 * pi) >= 0) a -= 2 * pi;
    a = min(a, 2 * pi - a);
    return a;
}
double cal(Vector v1, Vector v2){
    if(sgn(v1 % v2) == 0)
    {
        if(sgn(v1 * v2) > 0) return 0;
        else return -pi;
    }
    else{
        double a = angle(v1, v2);
        if(sgn(v1 % v2) > 0) a = - a;
        return a;
    }
}
int findone(int w, int v){
    double maxi = -100;
    Vector v1 = pv[v] - pv[w];
    int ans = 0;
    for(int i = head[v]; i != -1; i = e[i].next){
        int to = e[i].to;
        Vector v2 = pv[to] - pv[v];
        double a = cal(v1, v2);
        if(sgn(a - maxi ) > 0){
            maxi = a;
            ans = to;
        }
    }
    return ans;
}

vector<Point>route;
void solve(){
    int w = 1;
    Point minp = Point(1e9, 1e9);
    for(int i = 1; i <= nv; i++){
        if(pv[i] < minp){
            w = i;
            minp = pv[i];
        }
    }
    int v = 1;
    double mini = 1e9;
    for(int i = head[w]; i != -1; i = e[i].next){
        int to = e[i].to;
        Vector v1 = pv[to] - pv[w];
        double a = atan2(v1.y, v1.x);
        if(sgn(a - mini) < 0){
            mini = a;
            v = to;
        }
    }
    int w1 = w;
    //just go
    while(true){
        route.push_back(pv[w]);
        int newv = findone(w, v);
        w = v;
        v = newv;
        if(w == w1) break;
    }
}

int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        int x, y;
        scanf("%d%d",&x,&y);
        p[i] = Point(x, y);
    }
    build_edge();

    solve();

    //cal ans
    double ans = 0.0;
    for(int i = 0; i < route.size(); i++){
        int j = i + 1 == route.size() ? 0 : i + 1;
        ans += route[i] % route[j];
    }
    ans = abs(ans);
    ans = ans * 0.5;

    printf("%.10f\n",ans);

    return 0;
}

你可能感兴趣的:(Aizu 2448 Area Folding(复杂多边形求闭合面积并))