欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HDU 6325 Interstellar Travel【凸包】

程序员文章站 2022-03-30 08:33:51
...

题目链接

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

题目意思

平面有n个点,从1到n编号,现在开飞船从一个点到下一个点。给出你每个带你的坐标,要从 i 点到 j 点要求 xi < xj。飞船消耗的能量就是 xi * yj - xj * yi,消耗值可以为负数。现在问你从第一个点到第n个点的最小消耗情况下输出飞船经过的点的编号,按照字典序排列。

解题思路

看题意可以知道求两点之间的叉乘,并且消耗值可能为负数,所以我们就可以想到凸包,建立一个逆凸包,那么在凸包边上的点根据叉乘和小的按字典序输出即可。

代码部分

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
int qu[maxn],mn[maxn];///qu数组用于存储点的下标
struct node
{
    int x,y,id;
    bool operator<(const node &p)const///排序
    {
        if(x!=p.x) return x<p.x;
        if(y!=p.y) return y>p.y;
        return id<p.id;
    }
}pt[maxn];
ll get(int x,int y,int z)///求解xi*yj-xj*yi
{
    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-1LL*ay*bx;
}
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].id=i;///编号
        }
        sort(pt+1,pt+n+1);
        int now=0;///记录加入凸包的点的个数
        qu[0]=1;///凸包的顶点
        for(int i=2; i<=n; i++)///求解上凸包
        {
            if(pt[i].x==pt[i-1].x)
                continue;
            while(now&&get(qu[now-1],qu[now],i)>0)
                now--;
            qu[++now]=i;
        }
        int l=0,r;
        printf("1");
        while(l<now)
        {
            for(r=l+1; r<=now; r++)
            {
                if(get(qu[l],qu[l+1],qu[r])!=0)///判断是否存在共线
                    break;
            }
            mn[r]=1e9;
            for(int i=r-1; i>=l; i--)
            {
                mn[i]=min(pt[qu[i]].id,mn[i+1]);
            }
            for(int i=l+1; i<=r-1; i++)
            {
                if(mn[i]==pt[qu[i]].id)
                    printf(" %d",pt[qu[i]].id);
            }
            l=r-1;
        }
        cout<<endl;
    }
    return 0;
}