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 n planets in space, labeled by 1 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 (xi,yi).
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×yjxj×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(1T10) T ( 1 ≤ T ≤ 10 ) , denoting the number of test cases.
In each test case, there is an integer n(2n200000) n ( 2 ≤ n ≤ 200000 ) in the first line, denoting the number of planets.
For the next n n lines, each line contains 2 integers xi,yi(0xi,yi109) 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,...,xn1<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(1pin) p 1 , p 2 , . . . , p m ( 1 ≤ p i ≤ n ) , denoting the route you chosen is p1p2...pm1pm p 1 → p 2 → . . . → p m − 1 → p m . Obviously p1 p 1 should be 1 1 and pm 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 a is lexicographically smaller than a sequence of b b if there exists such index j 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×yjxj×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 倍。熟悉这个的话,就比较容易想到从这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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值