题目链接:
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;
}