woj 1097 Circle (圆的面积并)

这两天算是整个浑浑噩噩的过了吧,感觉过的头脑甚是不清晰。晚上看到群信息有人在讨论woj,于是上去随便翻开了第一页,发现这个题没有做。一看分数是1的,以为是当初看到的简单题没有做,结果一看题目,求圆的面积并,并不是很简单。

关于圆的面积并,之前知道一个做法,也在区域赛的时候准备了模版,但从来没有真正写过这个代码,左右无事,就把这个代码写出来了。

这里用的是一个很不错的算法,关于算法请参考:http://wenku.baidu.com/view/2d2e730979563c1ec5da719c.html

这篇文章当中给出来算法的pascal代码,这里我用C++写了一遍,顺便用woj 1097做了测试。

/*
 * Author: stormdpzh
 * Created Time:  2013/4/4 22:44:20
 * File Name: woj_1097.cpp
 */
#include <iostream>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <algorithm>
#include <functional>

#define sz(v) ((int)(v).size())
#define rep(i, n) for(int i = 0; i < n; i++)
#define repf(i, a, b) for(int i = a; i <= b; i++)
#define repd(i, a, b) for(int i = a; i >= b; i--)
#define out(n) printf("%d\n", n)
#define mset(a, b) memset(a, b, sizeof(a))
#define lint long long

using namespace std;

const int INF = 1 << 30;
const int MaxN = 105;
const double eps = 1e-9;
const int chash = 12343;
const double pie = acos(-1.0);

int n, nodes;
double x[MaxN], y[MaxN], r[MaxN];
double ans;
int l_link[10 * MaxN], next[10 * MaxN];
double node[10 * MaxN][2];
int first[chash + 5];

int sgn(double d)
{
    if(d > eps) return 1;
    if(d < -eps) return -1;
    return 0;
}

struct Inter
{
    double x, y;
    Inter() {}
    bool operator < (const Inter &t) const {
        if(sgn(x - t.x) == 0) return (y < t.y);
        else return x < t.x;
    }
};
Inter inter[MaxN];

double get_dist(double x1, double y1, double x2, double y2)
{
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

void init()
{
    for(int i = 1; i <= n; i++) {
        scanf("%lf%lf", &x[i], &y[i]);
        r[i] = 1.0;
    }
    bool b[MaxN];
    mset(b, true);
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++) {
            if(sgn(x[i] - x[j]) == 0 && sgn(y[i] - y[j]) == 0 && sgn(r[i] - r[j]) == 0) {
                b[i] = false;
                break;
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= n; j++) {
            if(i != j && sgn(r[i] - r[j]) < 0) {
                if(sgn(get_dist(x[i], y[i], x[j], y[j]) - (r[j] - r[i])) <= 0) {
                    b[i] = false;
                    break;
                }
            }
        }
    }
    int j = 0;
    for(int i = 1; i <= n; i++) {
        if(b[i]) {
            j++;
            x[j] = x[i];
            y[j] = y[i];
            r[j] = r[i];
        }
    }
    n = j;
}

double get_angle(double x, double y)
{
    if(sgn(x) < 0) return atan(y / x) + pie;
    else if(sgn(x) > 0) {
        if(sgn(y) > 0) return atan(y / x);
        else return atan(y / x) + pie * 2.0;
    }
    else if(sgn(y) > 0) return pie / 2.0;
    else return pie * 3.0 / 2.0;
}

void get_cross(int i, int j, double &t1, double &t2)
{
    double a, b, c, a1, b1, c1, x1, y1, x2, y2, t, l;
    a = (x[i] - x[j]) * 2.0;
    b = (y[i] - y[j]) * 2.0;
    c = r[j] * r[j] - r[i] * r[i] + x[i] * x[i] - x[j] * x[j] + y[i] * y[i] - y[j] * y[j];
    a1 = b;
    b1 = -a;
    c1 = a1 * x[i] + b1 * y[i];
    t = a * b1 - b * a1;
    x1 = (c * b1 - b * c1) / t;
    y1 = (a * c1 - c * a1) / t;
    l = sqrt(r[i] * r[i] - (x1 - x[i]) * (x1 - x[i]) - (y1 - y[i]) * (y1 - y[i]));
    t = sqrt(a1 * a1 + b1 * b1);
    x2 = x1 + l * a1 / t;
    y2 = y1 + l * b1 / t;
    x1 = x1 * 2.0 - x2;
    y1 = y1 * 2.0 - y2;
    t1 = get_angle(x1 - x[i], y1 - y[i]);
    t2 = get_angle(x2 - x[i], y2 - y[i]);
    if(sgn(t2 - t1) < 0) t1 = t1 - pie * 2.0;
    t = (t1 + t2) / 2.0;
    if((get_dist(x[j], y[j], x[i] + r[i] * cos(t), y[i] + r[i] * sin(t)) - r[j]) > 0) {
        t = t1;
        t1 = t2;
        t2 = t;
        if(sgn(t2) <= 0) t2 = t2 + pie * 2.0;
        else t1 = t1 - pie * 2.0;
    }
}

int get_index(double x, double y)
{
    int i, t;
    t = (int)(fabs(x + y + eps) * 100000) % chash;
    i = first[t];
    while(i != 0) {
        if(sgn(node[i][0] - x) == 0 && sgn(node[i][1] - y) == 0) {
            return i;
        }
        i = next[i];
    }
    nodes++;
    node[nodes][0] = x;
    node[nodes][1] = y;
    next[nodes] = first[t];
    first[t] = nodes;
    return nodes;
}

double get_chord(double r, double a)
{
    return r * r / 2.0 * (a - sin(a));
}

void get_node()
{
    int i, j, k, top, t1, t2;
    nodes = 0;
    for(i = 1; i <= n; i++) {
        top = 0;
        for(j = 1; j <= n; j++) {
            if(i != j && sgn(get_dist(x[i], y[i], x[j], y[j]) - (r[i] + r[j])) < 0) {
                top++;
                get_cross(i, j, inter[top].x, inter[top].y);
            }
        }
        if(top > 0) {
            sort(inter + 1, inter + top + 1);
            k = 0;
            for(j = 1; j <= top; j++) {
                if(k == 0 || sgn(inter[j].x - inter[k].y) > 0) {
                    k++;
                    inter[k].x = inter[j].x;
                    inter[k].y = inter[j].y;
                }
                else {
                    if(sgn(inter[j].y - inter[k].y) > 0) {
                        inter[k].y = inter[j].y;
                    }
                }
            }
            top = k;
            while(top > 0 && sgn(inter[top].y - (inter[1].x + pie * 2.0)) >= 0) {
                if(sgn(inter[top].x - pie * 2.0 - inter[1].x) < 0) {
                    inter[1].x = inter[top].x - pie * 2.0;
                }
                top--;
            }
            if(top > 0) {
                for(j = 1; j <= top - 1; j++) {
                    ans += get_chord(r[i], inter[j + 1].x - inter[j].y);
                    t1 = get_index(x[i] + r[i] * cos(inter[j + 1].x), y[i] + r[i] * sin(inter[j + 1].x));
                    t2 = get_index(x[i] + r[i] * cos(inter[j].y), y[i] + r[i] * sin(inter[j].y));
                    l_link[t1] = t2;
                }
                ans = ans + get_chord(r[i], inter[1].x + pie * 2.0 - inter[top].y);
                t1 = get_index(x[i] + r[i] * cos(inter[1].x), y[i] + r[i] * sin(inter[1].x));
                t2 = get_index(x[i] + r[i] * cos(inter[top].y), y[i] + r[i] * sin(inter[top].y));
                l_link[t1] = t2;
            }
        }
        else {
            ans += pie * r[i];
        }
    }
}

void gao()
{
    int i, j;
    bool vis[MaxN * 10];
    ans = 0.0;
    get_node();
    mset(vis, false);
    for(int i = 1; i <= nodes; i++) {
        if(!vis[i]) {
            j = i;
            do {
                vis[j] = true;
                ans += (node[l_link[j]][0] * node[j][1] - node[j][0] * node[l_link[j]][1]) / 2;
                j = l_link[j];
            } while(j != i);
        }
    }
}

int main()
{
    while(1 == scanf("%d", &n)) {
        init();
        gao();
        printf("%.2lf\n", ans);
    }
    return 0;
}


你可能感兴趣的:(woj 1097 Circle (圆的面积并))