SGU 209 Areas

首先处理出所有交点,并给所有点标号,注意合并相同的点。


然后给直接相连的两点之间连两条有向边,处理成邻接表。显然至多有O(n^2)个点和O(n^2)条边。


最后算法的核心就是枚举所有边作为起始边,“走”出所有的区域。


“走”的算法是这样的,每走到一个顶点,就找从这个点出发相对当前边的方向最“左”的边。


如果最后回到了最初枚举的起点就找到了一个有限区域。


如果这条边不在当前边的方向的“左”边说明这不是一个有限区域。否则更新当前边继续找。


对于“走”过的边标上标记,则以后遇到可以不再继续搜下去。


而在找从一个点出发相对当前边的方向最“左”的边的时候可以先对所有边按极角排序再二分查找。


其实这个找的过程在纸上模拟还是非常简单的,不过变成代码就可能有各种bug了……

A - Areas

Time Limit:  10000/5000MS (Java/Others)  Memory Limit:  128000/64000KB (Java/Others)      Special Judge
Submit Status

Problem Description

      Consider N different lines on the plane. They divide it to several parts, some of which are finite, some infinite.

      Your task in this problem is for each finite part to find its area.

Input

      The first line of the input file contains N —— the number of lines (1 ≤ N ≤ 80). Each of next N lines contains four integer numbers x1, y1, x2 and y2 - the coordinates of two different points of the line.

      All coordinates do not exceed 102 by their absolute value.

      No two lines coincide.

Output

      First output K - the number of finite parts among those the lines divide the plane to.

      Next K lines of the output file must contain area parts sorted in non-decreasing order. You answer must be accurate up to 10-4.

      Due to floating point precision losses possible, do not consider parts with area not exceeding 10-8.

Sample Input

5
0 0 1 0
1 0 1 1
1 1 0 1
0 1 0 0
0 0 1 1

Sample Output

2
0.5000
0.5000

Hint

戳我下载全套pdf
/*
* this code is made by xtu_zilean
* Problem: 1226
* Verdict: Accepted
* Submission Date: 2014-10-05 12:37:48
* Time: 76MS
* Memory: 4764KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#include <vector>
#define SIZE(X) ((int)(X.size()))
#define PB push_back
#define MP make_pair
#include <algorithm>
typedef pair<double, double> Point;
#define x first
#define y second
#define point Point
const double eps = 1e-8;
const double pi = acos(-1);
const int maxm = 200000;
const int maxp = 20000;
const int maxn = 90;
 
int e[maxm], prev[maxm], mark[maxm], tote;
int info[maxp];
 
int N, P;
Point a[111], b[111], p[maxp];
int cmp(double x) { return x<-eps?-1:x>eps; }
bool zero(double x) { return cmp(x)==0; }
 
Point operator-(Point a, Point  b)
{
    return MP(a.x-b.x, a.y-b.y);
}
Point operator*(Point a, double k)
{
    return Point(a.x*k, a.y*k);
}
point operator / (point a, double k)
{
    return point(a.x/k, a.y/k);
}
double getAngle(point a)
{
    return atan2(a.y, a.x);
}
double det(point a, point b)
{
    return a.x*b.y - a.y*b.x;
}
bool operator==(point a,point b)
{
    return zero(a.x-b.x) && zero(a.y-b.y);
}
bool intersect(const point &a, const point &b, const point &c, const point &d, point &res)
{
    double k1 = det(b-a, c-a), k2 = det(b-a, d-a);
    if(zero(k1 - k2)) return false;
    res = (d*k1 - c*k2) / (k1 - k2);
    return true;
}
void addedge(int x, int y)
{
    e[tote] = y; prev[tote] = info[x]; info[x] = tote++;
    e[tote] = x; prev[tote] = info[y]; info[y] = tote++;
}
vector<double> Divide()
{
    P = 0;
    for(int i=0;i<N;i++)
        for(int j=i+1;j<N;j++)
    {
        if(intersect(a[i],b[i], a[j],b[j], p[P])) P++;
    }
    sort(p, p+P);
    int tot = 1;
    for(int i=1;i<P;i++) if(!(p[i]==p[tot-1]))
        p[tot++] = p[i];
    P = tot;
    memset(info, 0, sizeof info);
    tote = 2;
    for(int i=0;i<N;i++) {
        int last = -1;
        for(int j=0;j<P;j++)
        if(zero(det(b[i]-a[i], p[j]-a[i]))) {
            if(last != -1) addedge(last, j);
            last = j;
        }
    }
    memset(mark, 0, sizeof mark);
    vector<double> area;
    for(int i=2;i<tote;i++) if(!mark[i]) {
        int laste = i ^ 1;
        int lastp = e[i];
        int head = e[laste];
        mark[i] = true;
        double ans;
        for(ans=det(p[head], p[lastp]); lastp!=head; ) {
            double best = 1e20;
            int cur = -1;
            double base = getAngle(p[e[laste]] - p[lastp]);
            for(int k = info[lastp]; k; k=prev[k]) if(k - laste)
            {
                double tmp = getAngle(p[e[k]] - p[lastp]) - base;
                if(tmp < 0) tmp += pi*2;
                if(tmp >= pi*2) tmp -= pi*2;
                if(tmp < best) {
                    best = tmp;
                    cur = k;
                }
            }
            ans += det(p[lastp], p[e[cur]]);
            lastp = e[cur];
            laste = cur ^ 1;
            mark[cur] = true;
        }
        area.PB(fabs(ans) *.5);
    }
    sort(area.begin(), area.end());
    if(SIZE(area)) area.erase(area.end()-1);
    return area;
}
int main()
{
    while(scanf("%d", &N)==1)
    {
        for(int i=0;i<N;i++) scanf("%lf%lf%lf%lf", &a[i].x, &a[i].y, &b[i].x, &b[i].y);
        vector<double> ans = Divide();
        int sz = SIZE(ans);
        printf("%d\n",sz);
        for(int i=0;i<sz;i++) printf("%.5f\n", ans[i]);
    }
}



你可能感兴趣的:(SGU 209 Areas)