杭电多校第三场 1007 HDU-6325 Interstellar Travel(凸包)

Problem G. Interstellar Travel
Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 514    Accepted Submission(s): 102


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个点,起点为横坐标的点,终点为横坐标最大的点。每次只能从一个点飞到一个横坐标严格大于它的点,而从点A(xa,ya)移动到B(xb,yb)的花费为xa*yb-xb*ya。现在问你从起点飞到终点的最小花费,输出字典序最小的移动路线。

题目思路:可以发现两点之间的花费就是两个点坐标的叉积,那么一条路径的总花费就是这几个点叉积的和。由于从起点到终点肯定是沿着顺时针的方向走一条路径,我们再从终点往起点连一条路,这样整条路径就围成了一个凸包,由于是顺时针围成的凸包,面积肯定是负的,要使得花费最小,我们就要尽可能的维护一个面积的绝对值较大的凸包,这样就能使花费最小。

这个题还有几个要注意的点,第一是有重复点的情况,这种情况下由于要使得字典序最小,所以我们保留标号最小的点即可,还有一种情况是多点共线的情况,我们对于线段两端的点是一定要保留下来的,再对于线上的点,取字典序最小即可。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+r,rt<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define MP make_pair
#define clr(a) memset(a,0,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
const int MX=2e5+7;

int n,_;
struct Point{
	ll x,y;
	int id;

	Point(ll x=0,ll y=0):x(x),y(y){}
	bool operator<(const Point&A)const{
		if(x != A.x) return x < A.x;
		if(y != A.y) return y > A.y;
		return id < A.id;
	}
}p[MX],q[MX];
Point operator-(Point A,Point B){
	return Point(A.x-B.x,A.y-B.y);
}
int ans[MX],vis[MX];

ll Cross(Point A,Point B){
	return A.x*B.y-A.y*B.x;
}

int main(){
	//FIN;
	for(scanf("%d",&_);_;_--){
		scanf("%d",&n);
		for(int i = 1;i <= n;i++){
			scanf("%lld%lld",&p[i].x,&p[i].y);
			p[i].id = i;vis[i] = 0;ans[i] = 0;
		}
		sort(p+1,p+n+1);
		int sz = 0;
		for(int i = 1;i <= n;i++){
			if(i>1 && p[i].x==p[i-1].x) continue;
			while(sz > 1 && Cross(p[i]-q[sz],q[sz]-q[sz-1]) < 0) sz--;
			q[++sz] = p[i];
		}
		vis[1] = vis[sz] = 1;
		for(int i = 2;i < sz;i++){
			if(Cross(q[i+1]-q[i],q[i]-q[i-1]) != 0)
				vis[i]=1;
		}
		for(int i=sz;i>=1;i--){
			if(vis[i]) ans[i] = q[i].id;
			else ans[i] = min(ans[i+1],q[i].id);
		}
		for(int i=1;i<sz;i++){
			if(ans[i] == q[i].id)
				printf("%d ",ans[i]);
		}
		printf("%d\n",ans[sz]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Lee_w_j__/article/details/81297107