Problem G. 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, 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 x i < x j , 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

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6;//eps用于控制精度
const double pi = acos(-1.0);//pi
struct Point//点或向量
{
    double x, y;
    int id,fin;
    Point() {}
    Point(double x, double y) :x(x), y(y) {}
};
typedef Point Vector;
Vector operator + (Vector a, Vector b)//向量加法
{
    return Vector(a.x + b.x, a.y + b.y);
}
Vector operator - (Vector a, Vector b)//向量减法
{
    return Vector(a.x - b.x, a.y - b.y);
}
Vector operator * (Vector a, double p)//向量数乘
{
    return Vector(a.x*p, a.y*p);
}
Vector operator / (Vector a, double p)//向量数除
{
    return Vector(a.x / p, a.y / p);
}
int dcmp(double x)//精度三态函数(>0,<0,=0)
{
    if (fabs(x) < eps)return 0;
    else if (x > 0)return 1;
    return -1;
}
bool operator == (const Point &a, const Point &b)//向量相等
{
    return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
}
double Dot(Vector a, Vector b)//内积
{
    return a.x*b.x + a.y*b.y;
}
double Length(Vector a)//模
{
    return sqrt(Dot(a, a));
}
double Angle(Vector a, Vector b)//夹角,弧度制
{
    return acos(Dot(a, b) / Length(a) / Length(b));
}
double Cross(Vector a, Vector b)//外积
{
    return a.x*b.y - a.y*b.x;
}
Vector Rotate(Vector a, double rad)//逆时针旋转
{
    return Vector(a.x*cos(rad) - a.y*sin(rad), a.x*sin(rad) + a.y*cos(rad));
}
double Distance(Point a, Point b)//两点间距离
{
    return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
double Area(Point a, Point b, Point c)//三角形面积
{
    return fabs(Cross(b - a, c - a) / 2);
}
int n, top;
Point P[600005], result[600005];
bool cmp(Point A, Point B)
{
    if(A.x==B.x&&A.y==B.y)
        return A.id<B.id;
    if(A.x==B.x)
        return A.y<B.y;
    return A.x<B.x;
}
void Graham()//Graham凸包扫描算法
{
    sort(P + 1, P + n, cmp);//水平排序
    int all=0;
    for(int i=1;i<n;i++)
    {
        if(P[all].x!=P[i].x||P[all].y!=P[i].y)
            P[++all]=P[i];
    }
    n=all+1;
    top = 0;
    for (int i = 0; i < n; i++)
    {
        while (top>1&&Cross(result[top-1] - result[top - 2], P[i] - result[top - 2]) > 0)
            top--;
        while(top>1&&Cross(result[top-1] - result[top - 2], P[i] - result[top - 2]) == 0 && result[top-1].id>P[i].id)
            top--;
        result[top++] = P[i];
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        scanf("%lf%lf",&P[0].x,&P[0].y);
        P[0].id=1;
        for(int i=n-1;i>=1;i--)
        {
            scanf("%lf%lf",&P[i].x,&P[i].y);
            P[i].id=n-i+1;
        }
        Graham();
        for(int i=0;i<top;i++)
        {
            printf("%d%c",result[i].id,i==top-1?'\n':' ');
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/82711047