UVALive 4617 Simple Polygon(顺/逆时针输出所有点/极角排序)

该博客主要解析UVALive 4617题目的解决方案,涉及如何利用极角排序确定平面点的顺/逆时针顺序,并讨论如何处理凸包问题。首先找到最左下角的点,然后对剩余点进行极角排序,通过去除共线点得到逆时针顺序的点序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:
UVALive 4617 Simple Polygon
题意:
将平面所有点都用上,构成一个多边形,顺时针(或逆时针)输出点的顺序。
分析:
多边形有可能是凸的也有可能是凹的。
先找到最左下角的点(x值优先),然后对其余点以最左下角为基点极角排序。除去最左侧的一系列和point[0]共线的点,其余的点的顺序即是逆时针的点的顺序。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <climits>
using namespace std;
const int MAX_N=2010;
const double eps=1e-10;

int T,n;
int ans[MAX_N];

struct Point{
    double x,y;
    int index;

    Point () {}
    Point (double x,double y) : x(x),y(y) {
    }
    Point operator + (const Point& rhs) const{
        return Point(x+rhs.x,y+rhs.y);
    }
    Point operator - (const Point& rhs) const {
        return Point(x-rhs.x,y-rhs.y);
    }
    Point operator * (const double d) const {
        return Point(d*x,d*y);
    }
    double dis(const Point& rhs) const{
        return sqrt((x-rhs.x)*(x-rhs.x)+(y-rhs.y)*(y-rhs.y));
    }
    double dot(const Point& rhs) const{
        return (x*rhs.x-y*rhs.y);
    }
    double cross(const Point& rhs) const{
        return (x*rhs.y-y*rhs.x);
    }
}point[MAX_N];

inline bool cmp(Point a,Point b)
{//按照最左下角极角排序
    double res=(a-point[0]).cross(b-point[0]);
    if(res!=0.0) return res>0;//res>0说明b在左侧,此时a的极角较小
    else return a.dis(point[0])<b.dis(point[0]); //共线时按照距离从小到大排序
}

inline void solve()
{
    //找到最左下角顶点,优先x最小,其次y最小
    int k=0;
    for(int i=0;i<n;i++){
        if(point[i].x<point[k].x||(point[i].x==point[k].x&&point[i].y<point[k].y)){
            k=i;
        }
    }
    swap(point[0],point[k]);
    sort(point+1,point+n,cmp); //排序从下标1开始,因为point[0]就是起点
    int end=n-2;
    //找到最后的顶点end,使得point[end],point[end+1]和point[0]不共线
    while(end>0){
        double res=(point[end]-point[0]).cross(point[end+1]-point[0]);
        if(res!=0.0) break;
        end--;
    }
    //从point[end+1]到point[n-1]都是和point[0]共线的点,即point[end+1]..point[n-1],point[0]都在一条直线上
    //因为极角排序时是按照到point[0]距离从小到大排序,所以这些点的逆时针顶点应该是按照距离从大到小考虑
    //point[end+1]实际上应该是第n-1个点,point[n-1]实际上应该时第end+1个点
    for(int i=end+1;i<n;i++){
        ans[i]=point[n+end-i].index;
    }
    for(int i=0;i<=end;i++){
        ans[i]=point[i].index;
    }
    for(int i=0;i<n;i++){
        printf("%d%c",ans[i],i==n-1?'\n':' ');
    }
}

int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%lf%lf",&point[i].x,&point[i].y);
            point[i].index=i;
        }
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值