Problem G. Interstellar Travel
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 524288/524288 K (Java/Others)
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
n
planets in space, labeled by to
n
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 .
Little Q plans to start his journey at the
1th
1
t
h
planet, and end at the
nth
n
t
h
planet. When he is at the
ith
i
t
h
planet, he can next fly to the
jth
j
t
h
planet only if
xi<xj
x
i
<
x
j
, which will cost his spaceship
xi×yj−xj×yi
x
i
×
y
j
−
x
j
×
y
i
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)
T
(
1
≤
T
≤
10
)
, denoting the number of test cases.
In each test case, there is an integer
n(2≤n≤200000)
n
(
2
≤
n
≤
200000
)
in the first line, denoting the number of planets.
For the next
n
n
lines, each line contains integers
xi,yi(0≤xi,yi≤109)
x
i
,
y
i
(
0
≤
x
i
,
y
i
≤
10
9
)
, 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
y
1
=
y
n
=
0
,
0
=
x
1
<
x
2
,
x
3
,
.
.
.
,
x
n
−
1
<
x
n
.
Output
For each test case, print a single line containing several distinct integers
p1,p2,...,pm(1≤pi≤n)
p
1
,
p
2
,
.
.
.
,
p
m
(
1
≤
p
i
≤
n
)
, denoting the route you chosen is
p1→p2→...→pm−1→pm
p
1
→
p
2
→
.
.
.
→
p
m
−
1
→
p
m
. Obviously
p1
p
1
should be
1
1
and should be
n
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 is lexicographically smaller than a sequence of
b
b
if there exists such index that
ai=bi
a
i
=
b
i
for all
i<j
i
<
j
, but
aj<bj
a
j
<
b
j
.
Sample Input
1
3
0 0
3 0
4 0
Sample Output
1 2 3
思路:观察代价
cost=xi×yj−xj×yi
c
o
s
t
=
x
i
×
y
j
−
x
j
×
y
i
。可以发现这是向量
(xi,yi)
(
x
i
,
y
i
)
与
(xj,yj)
(
x
j
,
y
j
)
的叉积,也就是由
(xi,yi)
(
x
i
,
y
i
)
,
(xj,yj)
(
x
j
,
y
j
)
,
(0,0)
(
0
,
0
)
三点构成的三角形的有向面积的
2
2
倍。熟悉这个的话,就比较容易想到从这个点中选出一些点构成一个上半凸包是最优的。
然后排序求个上半凸包。
接下来就是字典序的问题了。
因为求出来的是一个凸包,如果凸包上没有三点或三点以上共线的情况,那么肯定就把凸包上的点全部选中就OK了。
如果有,在多点共线的情况下,线段的2个端点肯定是必选的(不然就不是线段了)。只是对于处于线段中的点,如果选了那个点能使字典序变小,则选上,否则不选。
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
struct Point
{
ll x,y,id;
}p[MAX],q[MAX];
int cmp(const Point& A,const Point& B)
{
if(A.x!=B.x)return A.x<B.x;
if(A.y!=B.y)return A.y>B.y;
return A.id<B.id;
}
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y,0};}
ll cross(Point A,Point B){return A.x*B.y-A.y*B.x;}
int check(Point A,Point B,Point C){return cross(B-A,C-A)!=0;}
int v[MAX];
int ans[MAX];
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&p[i].x,&p[i].y);
p[i].id=i;
}
sort(p+1,p+n+1,cmp);
int R=0;
for(int i=1;i<=n;i++) //排序后求上半凸包
{
if(i>1&&p[i].x==p[i-1].x)continue;
while(R>=2&&(q[R].y-q[R-1].y)*(p[i].x-q[R].x)<(q[R].x-q[R-1].x)*(p[i].y-q[R].y))R--;
q[++R]=p[i];
}
for(int i=1;i<=R;i++)v[i]=0;
v[1]=v[R]=1;
for(int i=2;i<R;i++)v[i]=check(q[i-1],q[i],q[i+1]);//确定必选的点
for(int i=R;i>=1;i--) //对于没选中的点,和后面已经选的点进行比较,取字典序较小的
{
if(v[i])ans[i]=q[i].id;
else ans[i]=min((int)q[i].id,ans[i+1]);
}
for(int i=1;i<=R;i++)
{
if(ans[i]==q[i].id)printf("%d%c",ans[i],i==R?'\n':' ');
}
}
return 0;
}