lightoj 1285(凸包)

题意:有n个点,要求每个点都要是凸多边形的一个顶点,且边不交叉,每个点只有两条边和他相连,要求顺序输出凸多边形的形状也就是各个顶点的编号,不存在就输出Impossible。
题解:首先容易想到Impossible的情况只有n点共线时会出现,用凸包函数求出凸包后,如果少于3个点就是Impossible。特判后,再用一次凸包,这次求凸包要包括共线点,下凸包的点是答案数组的前半部分。然后把所有点(不是只有凸包上的点)排序从右到左,从上到下排序,最右边的点一定在凸包上,从最右边的点开始,按顺序保存未被访问过的点(也就是除下凸包外所有点)到答案数组里,这些点是答案数组的后半部分。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const double eps = 1e-9;
const double PI = acos(-1);

double Sqr(double x) { return x * x; }
int dcmp(double x) { if (fabs(x) < eps) return 0; return x > 0 ? 1 : -1; }

struct Point {
    double x, y;
    int id;
    Point(double a = 0, double b = 0): x(a), y(b) {}
};

typedef Point Vector;
typedef vector<Point> Polygon;

Vector operator + (const Vector& a, const Vector& b) { return Vector(a.x + b.x, a.y + b.y); }
Vector operator - (const Vector& a, const Vector& b) { return Vector(a.x - b.x, a.y - b.y); }
Vector operator * (const Vector& a, double b) { return Vector(a.x * b, a.y * b); }
Vector operator / (const Vector& a, double b) { return Vector(a.x / b, a.y / b); }
bool operator == (const Vector& a, const Vector& b) { return !dcmp(a.x - b.x) && !dcmp(a.y - b.y); }
bool operator < (const Vector& a, const Vector& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); }
double Dot(const Vector& a, const Vector& b) { return a.x * b.x + a.y * b.y; }
double Length(const Vector& a) { return sqrt(Dot(a, a)); }
double Cross(const Vector& a, const Vector& b) { return a.x * b.y - a.y * b.x; }
double Angle(const Vector& a, const Vector& b) { return acos(Dot(a, b) / Length(a) / Length(b)); }
double angle(Vector v) { return atan2(v.y, v.y); }

int ConvexHull1(Point* P, int cnt, Point* res) {
    sort(P, P + cnt);
    cnt = unique(P, P + cnt) - P;
    int m = 0;
    for (int i = 0; i < cnt; i++) {
        while (m > 1 && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    int k = m;
    for (int i = cnt - 2; i >= 0; i--) {
        while (m > k && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) <= 0)
            m--;
        res[m++] = P[i];
    }
    if (cnt > 1) m--;
    return m;
}

int ConvexHull(Point* P, int cnt, Point* res, int* num) {
    sort(P, P + cnt);
    cnt = unique(P, P + cnt) - P;
    int m = 0;
    for (int i = 0; i < cnt; i++) {
        while (m > 1 && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) < 0)
            m--;
        num[m] = P[i].id;
        res[m++] = P[i];
    }
    int k = m;
    for (int i = cnt - 2; i >= 0; i--) {
        while (m > k && Cross(res[m - 1] - res[m - 2], P[i] - res[m - 2]) < 0)
            m--;
        num[m] = P[i].id;
        res[m++] = P[i];
    }
    if (cnt > 1) m--;
    return m;
}

int cmp(Point a, Point b) {
    if (a.x != b.x)
        return a.x > b.x;
    return a.y > b.y;
}

const int N = 2 * 1e3 + 5;
int n, num[N], vis[N], ans[N];
Point P[N], res[N];

int main() {
    int t, cas = 1;
    scanf("%d", &t);
    while (t--) {
        int nnn = 0;
        memset(vis, 0, sizeof(vis));
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &P[i].x, &P[i].y);
            P[i].id = i;
        }
        int cnt1 = ConvexHull1(P, n, res);
        if (cnt1 <= 2) {
            printf("Case %d:\nImpossible\n", cas++);
            continue;
        }
        int cnt = ConvexHull(P, n, res, num);
        for (int i = 0; i < cnt; i++)
            vis[num[i]] = 1;
        sort(P, P + n, cmp);
        int id1 = P[0].id;
        printf("Case %d:\n", cas++);
        int i;
        for (i = 0; i < cnt; i++) {
            if (num[i] == id1)
                break;
            ans[nnn++] = num[i];
        }
        for (; i < cnt; i++)
            vis[num[i]] = 0;
        for (int j = 0; j < n; j++)
            if (!vis[P[j].id])
                ans[nnn++] = P[j].id;
        printf("%d", ans[0]);
        for (int j = 1; j < nnn; j++)
            printf(" %d", ans[j]);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值