2018 Multi-University Training Contest 3-1007:Problem G. Interstellar Travel(思维)

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 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 ( x i , y i ) .
Little Q plans to start his journey at the 1 t h planet, and end at the n t h planet. When he is at the i t h planet, he can next fly to the j t h planet only if x i < x j , which will cost his spaceship 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 ) , 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 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 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 p 1 , p 2 , . . . , p m ( 1 p i n ) , denoting the route you chosen is p 1 p 2 . . . p m 1 p m . Obviously p 1 should be 1 and p m 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 a i = b i for all i < j , but a j < b j .

Sample Input
1
3
0 0
3 0
4 0

Sample Output
1 2 3

思路:观察代价 c o s t = x i × y j x j × y i 。可以发现这是向量 ( x i , y i ) ( x j , y j ) 的叉积,也就是由 ( x i , y i ) , ( x j , y j ) , ( 0 , 0 ) 三点构成的三角形的有向面积的 2 倍。熟悉这个的话,就比较容易想到从这 n 个点中选出一些点构成一个上半凸包是最优的。
然后排序求个上半凸包。
接下来就是字典序的问题了。
因为求出来的是一个凸包,如果凸包上没有三点或三点以上共线的情况,那么肯定就把凸包上的点全部选中就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;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81290523
今日推荐