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, Littl 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

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

Sample Input



0 0 
3 0 
4 0

Sample Output

1 2 3

题目链接http://acm.hdu.edu.cn/webcontest/contest_showproblem.php?pid=1002&ojid=0&cid=12614&hide=0

题目描述:

问题g .星际旅行

问题描述

经过多年的努力,小Q终于获得了宇航员执照。为了庆祝这一事实,他打算给自己买一艘宇宙飞船,进行一次星际旅行。

小Q知道n个行星在空间中的位置,被1到n标记,令他吃惊的是,这些行星都是共面的。为了简化,小Q把这n颗行星放在平面坐标系中,计算出每颗行星的坐标(xi,yi)

小Q计划在第1颗行星开始他的旅程,在第n颗行星结束。当他在第i个行星时,他可以从第i行星上飞到第j个行星,这将花费他的飞船xi*yj-xj*yi单位的能量。注意,这个成本可以是负的,这意味着飞行将为他的宇宙飞船提供补给。

请编写一个程序帮助小Q以最小的总成本找到最佳路线。

输入

输入的第一行包含一个整数T(1≤T≤10),表示测试用例的数量。

在每个测试用例,一个整数n(2≤n≤200000)在第一线,表示数量的行星。

在接下来的n行,每一行包含两个整数,xi,yi(0≤xi,yi≤10^9)表示第i个星球的坐标。注意,不同的行星可能有相同的坐标,因为它们彼此太接近了。测试数据保证“y1=yn=0,0=x1<x2,x3,...,xn−1<xn. ”

输出

对于每个测试用例,打印一行包含几个不同的整数p1,p2,…,pm(1≤pi≤n),表示你选择的路线是p1→p2→…→pm−1→pm。显然p1应该是1,pm应该是n,你应该选择总成本最小的路线。如果有多个最佳路径,请选择字典上最小的路径。

一个整数序列A在字典上比b的序列要小,如果存在这样的索引j 使ai=bi对于所有i<j,aj<bj

思路

由于从i星球到j星球需要消耗的能量为 xi×yj−xj×yicost=xi×yj−xj×yi。可以发现这是一个求向量叉积的题,因为要使总成本最小。且这个成本可以是负的,那么负的越大,成本越小,这样我们就可以想到用凸包。 
又要求按字典序最小输出。 那么我们就要去掉一些不必要的点: 
求出来的是一个凸包,如果凸包上没有三点或三点以上共线的情况,那么就直接把凸包上的点全部输出就好了。 
但是如果有多点共线的情况,线段的2个端点肯定是必选的(不然就不是线段了)。只是对于处于线段中的点,如果选了那个点能使字典序变小,则选上,否则不选。

凸包的模板:

题目代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
struct node
{
    int x,y,ps;
    bool operator<(const node &p)const
    {
        if(x!=p.x)
            return x<p.x;
        if(y!=p.y)
            return y>p.y;
        return ps<p.ps;
    }
}pt[N];
long long get(int x,int y,int z)
{
    int ax=pt[y].x-pt[x].x;
    int ay=pt[y].y-pt[x].y;
    int bx=pt[z].x-pt[y].x;
    int by=pt[z].y-pt[y].y;
    return 1LL*ax*by-ay*bx;
}
int mn[N];
int que[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i>+n;i++)
        {
            scanf("%d %d",&pt[i].x,&pt[i].y);
        }
        for(int i=1;i<=n;i++)
        {
            pt[i].ps=i;
        }
        sort(pt+1,pt+n+1);
        int now=0;
        que[0]=1;
        for(int i=2;i<=n;i++)
        {
            if(pt[i].x==pt[i-1].x)
                continue;
            while(now&&get(que[now-1],que[now],i)>0)
                now--;
            que[++now]=i;
        }
        int l=0,r;
        printf("1");
        while(l<now)
        {
            for(r=l+1;r<=now;r++)
            {
                if(get(que[1],que[l+1],que[r])!=0)
                    break;
            }
            mn[r]=1e9;
            for(int i=r-1;i>=l;i--)
            {
                mn[i]=min(pt[que[i]].ps,mn[i+1]);
            }
            for(int i=l+1;i<=r-1;i++)
            {
                if(mn[i]==pt[que[i]].ps)
                    printf(" %d",pt[que[i]].ps);
            }
            l=r-1;
        }
        puts("");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pdsu_congshuang/article/details/81393916
今日推荐