Problem G. Interstellar Travel
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1473 Accepted Submission(s): 357
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
Source
2018 Multi-University Training Contest 3
Recommend
chendu | We have carefully selected several similar problems for you: 6343 6342 6341 6340 6339
【思路】
整条路径的叉积和最小意味着绝对值最大,因此也就相当于找一个以x轴为下边界的凸包,同时要求点序的字典序最小,我们便要在凸包上选合适的点,拐角之间的共线点找一串序号严格单增的即可,因此直接扫一遍用转角法搞一下上凸包即可。注意重合点与共线情况的判定。
【代码】
//******************************************************************************
// File Name: G.cpp
// Author: Shili_Xu
// E-Mail: shili_xu@qq.com
// Created Time: 2018年08月02日 星期四 22时21分14秒
//******************************************************************************
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
struct point {
long long x, y;
int id;
point(long long _x = 0, long long _y = 0, int _id = 0) : x(_x), y(_y), id(_id) {}
bool operator<(const point &another) const
{
if (x == another.x && y == another.y) return id < another.id;
return (x < another.x) || (x == another.x && y < another.y);
}
};
typedef point vec;
vec operator-(point a, point b)
{
return vec(a.x - b.x, a.y - b.y);
}
long long det(vec a, vec b)
{
return a.x * b.y - a.y * b.x;
}
int t, n;
vector<point> p, ans;
int main()
{
scanf("%d", &t);
while (t--) {
p.clear(); ans.clear();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
long long x, y;
scanf("%lld %lld", &x, &y);
p.push_back(point(x, y, i));
}
sort(p.begin(), p.end());
ans.push_back(p[0]); ans.push_back(p[1]);
for (int i = 2; i < p.size(); i++) {
if (ans.back().x == p[i].x && ans.back().y == p[i].y) continue;
while (ans.size() >= 2 && (det(ans.back() - ans[ans.size() - 2], p[i] - ans[ans.size() - 2]) > 0
|| (det(ans.back() - ans[ans.size() - 2], p[i] - ans[ans.size() - 2]) == 0 && p[i].id < ans.back().id))) ans.pop_back();
ans.push_back(p[i]);
}
for (int i = 0; i < ans.size(); i++)
printf("%d%c", ans[i].id, " \n"[i == (int)ans.size() - 1]);
}
return 0;
}