1. 程式人生 > >Problem G. Interstellar Travel——水平排序凸包

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

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

#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; }