Problem G. Interstellar Travel
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1333 Accepted Submission(s): 316
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 xi<xj, which will cost his spaceship xi×yj−xj×yi units of energy. Note that this cost can be negative, it means the flight will supply his spaceship.
Please write a program to help Little Q find the best route with minimum total cost.
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<x2,x3,...,xn−1<xn.
Output
For each test case, print a single line containing several distinct integers p1,p2,...,pm(1≤pi≤n), denoting the route you chosen is p1→p2→...→pm−1→pm. Obviously p1 should be 1 and pm should be n. You should choose the route with minimum total cost. If there are multiple best routes, please choose the one with the smallest lexicographically.
A sequence of integers a is lexicographically smaller than a sequence of b if there exists such index j that ai=bi for all i<j, but aj<bj.
Sample Input
1 3 0 0 3 0 4 0
Sample Output
1 2 3
Source
2018 Multi-University Training Contest 3
对于一个凸包而言,逆时针走叉积最大,顺时针走叉积最小。
那么,肯定是顺时针走,考虑到起始位置跟终止位置的特点,所以只要维护上凸包就可以了。
对于共线的点,考虑该点是否能让字典序更小即可。
#include<bits/stdc++.h>
#define mp make_pair
#define fir first
#define se second
#define ll long long
#define pb push_back
using namespace std;
const int maxn=2e5+10;
const ll mod=1e9+7;
const int maxm=1e6+10;
const double eps=1e-7;
const int inf=0x3f3f3f3f;
const double pi = acos (-1.0);
int dcmp ( double x)
{
if ( fabs (x) < eps) return 0;
return (x < 0 ? -1 : 1);
}
inline double sqr ( double x)
{
return x*x;
}
struct Point
{
double x, y;
int id;
Point ( double _x = 0, double _y = 0):x(_x), y(_y) {}
void input ()
{
scanf ( "%lf%lf", &x, &y);
}
void output ()
{
printf ( "%.2f %.2f\n", x, y);
}
bool operator == ( const Point &b) const
{
return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
}
bool operator < ( const Point &b) const
{
if (dcmp(x-b.x)==0&&dcmp(y-b.y)==0){
return id<b.id;
}
return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) > 0 : x < b.x);
}
Point operator + ( const Point &b) const
{
return Point (x+b.x, y+b.y);
}
Point operator - ( const Point &b) const
{
return Point (x-b.x, y-b.y);
}
Point operator * ( double a)
{
return Point (x*a, y*a);
}
Point operator / ( double a)
{
return Point (x/a, y/a);
}
double len2 ()
{
return sqr (x) + sqr (y);
}
double len ()
{
return sqrt (len2 ());
}
Point change_len ( double r)
{
double l = len ();
if (dcmp (l) == 0) return *this;
r /= l;
return Point (x*r, y*r);
}
Point rotate_left ()
{
return Point (-y, x);
}
Point rotate_right ()
{
return Point (y, -x);
}
Point rotate (Point p, double ang)
{
Point v = (*this)-p;
double c = cos (ang), s = sin (ang);
return Point (p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
}
Point normal ()
{
double l = len ();
return Point (-y/l, x/l);
}
};
double cross (Point a, Point b)
{
return a.x*b.y-a.y*b.x;
}
double cal(Point a,Point b){
return (a.y-b.y)/(a.x-b.x);
}
int k;
int convex_hull (Point *p, Point *ch, int n)
{
sort (p, p+n);
int m = 0;
for ( int i = 0; i < n; i++)
{
if (i>0&&p[i].x==p[i-1].x) continue;
while (m > 1 && cross (ch[m-1]-ch[m-2], p[i]-ch[m-1]) > 0)
m--;
ch[m++] = p[i];
//cout<<"m="<<m<<" i="<<i<<endl;
// ch[m-1].output();
}
/*k = m;
for ( int i = n-2; i >= 0; i--)
{
while (m > k && cross (ch[m-1]-ch[m-2], p[i]-ch[m-1]) <= 0)
m--;
ch[m++] = p[i];
}*/
/*if (n > 1)
m--;*/
return m;
}
int n;
Point p[maxn],ch[maxn];
int ans[maxn];
int vis[maxn];
int main(){
int t;
scanf("%d",&t);
while (t--){
scanf("%d",&n);
for (int i=0;i<n;i++){
p[i].input();
p[i].id=i+1;
}
Point temp=p[n-1];
int m=convex_hull(p,ch,n);
/* for (int i=0;i<m;i++){
ch[i].output();
}*/
for (int i=0;i<m;i++) vis[i]=0;
for (int i=0;i<m;i++) ans[i]=0;
ans[0]=1;
ans[m-1]=n;
vis[0]=vis[m-1]=1;
for (int i=1;i<m-1;i++){
if (cross(ch[i]-ch[i-1],ch[i+1]-ch[i-1])!=0){
vis[i]=1;
//抓出那些共线的点
}
}
for (int i=m-2;i>0;i--){
if (vis[i]){
ans[i]=ch[i].id;
}
else{
ans[i]=min(ans[i+1],ch[i].id);
}
}
int cnt=0;
for (int i=0;i<m;i++){
if (ch[i].id==ans[i]){
if (cnt==0){
printf("%d",ans[i]);
cnt++;
}
else{
printf(" %d",ans[i]);
cnt++;
}
}
}
printf("\n");
}
return 0;
}