UVALive 3218(求折线的轮廓)

题意:给一段折线,可以自交,保证首尾重合,把它的轮廓求出来

链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31691

解法:参照大白书的做法,先选一个起点,即最左下角的点,再选第一条出边,即角度最小点边,开始走,找到所有与该边相交的点但不和该边起点一样交点,找到最近的一个,如果有多个,找到出去方向拐向最右的一个,不断地找,直到回到最初起点为止。。

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

#define N 200
int n;

const double eps = 1e-8, 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);
}
double operator % (Vector a, Vector b){
    return a.x * b.y - a.y * b.x;
}
Vector operator * (Vector a, double b){
    return Vector(a.x * b, a.y * b);
}
bool operator == (Point a, Point b){
    return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
}
Point getp(Point p1, Vector v1, Point p2, Vector v2, double &t){
    t = ((p2 - p1) % v2) / (v1 % v2);
    return p1 + v1 * t;
}
Point p[N];
bool inter(Point p1, Point p2, Point q1, Point q2){
    double t;
    if(sgn((p2 - p1) % (q2 - q1)) == 0) return false;
    getp(p1, p2 - p1, q1, q2 - q1, t);
    if(sgn(t) < 0 || sgn(t - 1) > 0) return false;
    getp(q1, q2 - q1, p1, p2 - p1, t);
    if(sgn(t) < 0 || sgn(t - 1) > 0) return false;
    return true;
}

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 - sgn(v1 % v2) * a;
}

void newp(Point &p1, Point &p2){
    double mind = 1e9, t, maxa = -100;
    Point newp1 = Point(-1e9, -1e9), newp2 = Point(-1e9, -1e9);
    for(int i = 0; i < n; i++){
        int j = i + 1 == n ? 0 : i + 1;
        if(sgn((p2 - p1) % (p[j] - p[i])) == 0) continue;
        if(p1 == p[i] || p1 == p[j]) continue;//!!
        if(inter(p1, p2, p[i], p[j]))
        {
            if((p2 == p[i]) == 0)
            {
                Point x = getp(p1, p2 - p1, p[j], p[i] - p[j], t);
                if((x == p1) == 0)
                {
                    double a = angle(p2 - p1, p[i] - p[j]);
                    if(sgn(t - mind) < 0){
                        mind = t;
                        maxa = a;
                        newp1 = x, newp2 = p[i];
                    }
                    else if(sgn(t - mind) == 0 && sgn(a - maxa) > 0){
                        maxa = a;
                        newp1 = x, newp2 = p[i];
                    }
                }
            }
            if((p2 == p[j]) == 0)
            {
                Point x = getp(p1, p2 - p1, p[i], p[j] - p[i], t);
                if((x == p1) == 0)
                {
                    double a = angle(p2 - p1, p[j] - p[i]);
                    if(sgn(t - mind) < 0){
                        mind = t;
                        maxa = a;
                        newp1 = x, newp2 = p[j];
                    }
                    else if(sgn(t - mind) == 0 && sgn(a - maxa) > 0){
                        maxa = a;
                        newp1 = x, newp2 = p[j];
                    }
                }
            }
        }
    }
    p1 = newp1, p2 = newp2;
}

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

        int w = 0;
        Point minp = Point(1e9, 1e9);
        for(int i = 0; i < n; i++){
            if(sgn(p[i].x - minp.x) < 0){
                w = i;
                minp = p[i];
            }
            else if(sgn(p[i].x - minp.x) == 0 && sgn(p[i].y - minp.y) < 0){
                w = i;
                minp = p[i];
            }
        }
        Point p1 = p[w] - Vector(0, 1), p2 = p[w];
        newp(p1, p2);

        vector<Point>res;
        res.clear();
        while(true){
            res.push_back(p1);
            newp(p1, p2);
            if(p1 == minp) break;
        }
        printf("%d\n", (int) res.size());
        for(int i = 0; i < res.size(); i++){
            printf("%.4f %.4f\n", res[i].x, res[i].y);
        }
    }
    return 0;
}

你可能感兴趣的:(UVALive 3218(求折线的轮廓))