Problem G. Interstellar Travel——水平排序凸包
Problem Description
After trying hard for many years, Little Q has finally received an astronaut license. To celebrate the fact, he intends to buy himself a spaceship and make an interstellar travel.
Little Q knows the position of n planets in space, labeled by 1 to n. To his surprise, these planets are all coplanar. So to simplify, Little Q put these n planets on a plane coordinate system, and calculated the coordinate of each planet (xi,yi).
Little Q plans to start his journey at the 1-th planet, and end at the n-th planet. When he is at the i-th planet, he can next fly to the j-th planet only if
Input The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases. In each test case, there is an integer n(2≤n≤200000) in the first line, denoting the number of planets. For the next n lines, each line contains 2 integers xi,yi(0≤xi,yi≤109), denoting the coordinate of the i-th planet. Note that different planets may have the same coordinate because they are too close to each other. It is guaranteed that y1=yn=0,0=x1
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6;//eps用於控制精度
const double pi = acos(-1.0);//pi
struct Point//點或向量
{
double x, y;
int id,fin;
Point() {}
Point(double x, double y) :x(x), y(y) {}
};
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);
}
Vector operator * (Vector a, double p)//向量數乘
{
return Vector(a.x*p, a.y*p);
}
Vector operator / (Vector a, double p)//向量數除
{
return Vector(a.x / p, a.y / p);
}
int dcmp(double x)//精度三態函式(>0,<0,=0)
{
if (fabs(x) < eps)return 0;
else if (x > 0)return 1;
return -1;
}
bool operator == (const Point &a, const Point &b)//向量相等
{
return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Dot(Vector a, Vector b)//內積
{
return a.x*b.x + a.y*b.y;
}
double Length(Vector a)//模
{
return sqrt(Dot(a, a));
}
double Angle(Vector a, Vector b)//夾角,弧度制
{
return acos(Dot(a, b) / Length(a) / Length(b));
}
double Cross(Vector a, Vector b)//外積
{
return a.x*b.y - a.y*b.x;
}
Vector Rotate(Vector a, double rad)//逆時針旋轉
{
return Vector(a.x*cos(rad) - a.y*sin(rad), a.x*sin(rad) + a.y*cos(rad));
}
double Distance(Point a, Point b)//兩點間距離
{
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
double Area(Point a, Point b, Point c)//三角形面積
{
return fabs(Cross(b - a, c - a) / 2);
}
int n, top;
Point P[600005], result[600005];
bool cmp(Point A, Point B)
{
if(A.x==B.x&&A.y==B.y)
return A.id<B.id;
if(A.x==B.x)
return A.y<B.y;
return A.x<B.x;
}
void Graham()//Graham凸包掃描演算法
{
sort(P + 1, P + n, cmp);//水平排序
int all=0;
for(int i=1;i<n;i++)
{
if(P[all].x!=P[i].x||P[all].y!=P[i].y)
P[++all]=P[i];
}
n=all+1;
top = 0;
for (int i = 0; i < n; i++)
{
while (top>1&&Cross(result[top-1] - result[top - 2], P[i] - result[top - 2]) > 0)
top--;
while(top>1&&Cross(result[top-1] - result[top - 2], P[i] - result[top - 2]) == 0 && result[top-1].id>P[i].id)
top--;
result[top++] = P[i];
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
scanf("%lf%lf",&P[0].x,&P[0].y);
P[0].id=1;
for(int i=n-1;i>=1;i--)
{
scanf("%lf%lf",&P[i].x,&P[i].y);
P[i].id=n-i+1;
}
Graham();
for(int i=0;i<top;i++)
{
printf("%d%c",result[i].id,i==top-1?'\n':' ');
}
}
return 0;
}