2018 Multi-University Training Contest 3 1007 / hdu6325 Problem G. Interstellar Travel 凸包

Problem G. Interstellar Travel

题意:
给定平面上n个点,起点1 为(0,0),终点 n 为(Xn, 0),其它点的横坐标 0 <Xi<Xn,纵坐标 Xi >=0。每次可以飞到一个横坐标严格更大的点,代价为两个坐标的叉积。求起点到终点总代价最小的飞行路线,并输出字典序最小的路线。2≤n≤200000。 Shortest judge solution: 979 bytes
题解:
显然坐标相同的点里只保留编号最小的点最优。
将起点到终点的路径补全为终点往下走到无穷远处,再往左走到起点正下方,再往上回到起点。
任意路径中回到起点部分的代价相同,观察代价和的几何意义,就是走过部分的面积的相反数。
代价和最小等价于面积最大,故一定是沿着上凸壳行走。
显然起点、终点、凸壳的拐点必须要作为降落点。
对于共线的点a1,a2,...,am,若一个点i的编号是[i,m]中最小的,那么在此处降落可以最小化字典序。时间复杂度O(nlogn)。

1、其实首先要明确从点1 直接到点 n 的花费是 0,所以再加入其它点的代价必须为负。
2、根据叉积的几何意义,面积要最大,那就是求凸包。
3、最皮的是要字典序最小输出,也就是在凸包边界线上的点也有可能要取。所以我们记录一下边界线上的点是否小于它到拐点之间的点。


#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005;

struct Point {
    ll  x, y;  int id;
    Point(ll x=0, ll y=0):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 -(Point A, Point B){ return Vector(A.x-B.x, A.y-B.y); }
bool operator <(const Point& a, const Point& b){
    if(a.x==b.x && a.y==b.y) return a.id < b.id;
    return a.x<b.x || (a.x==b.x && a.y<b.y);
}
ll  Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

bool used[N];
int mi[N];
void ConvexHull(Point* p, int n, Point* ch)
{
    sort(p, p+n);
    int m = 0;
    for(int i=0; i<n; ++i) {  //维护上凸包
        if(i>1 && p[i].x==p[i-1].x && p[i].y==p[i-1].y) continue;
        while(m>1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])>0) --m;
        ch[m++] = p[i];
    }
    mes(used, false);
    used[0] = used[m-1] = true;
    for(int i=1; i<m; ++i) {
        if(Cross(ch[i]-ch[i-1], ch[i+1]-ch[i-1]) != 0)
            used[i] = true;
    }
    for(int i=m; i>=0; --i) {
        if(used[i]) mi[i] = ch[i].id;
        else  mi[i] = min(mi[i+1], ch[i].id);
    }
    for(int i=0; i<m; ++i)
        if(mi[i] == ch[i].id)
            printf("%d%c", ch[i].id, " \n"[i==m-1]);
}
Point p[N];
Point vertex[N];
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        int n;  scanf("%d", &n);
        rep(i,1,n) scanf("%lld%lld", &p[i].x, &p[i].y), p[i].id=i;
        ConvexHull(p+1, n, vertex);
    }

    return 0;
}

原文地址:https://www.cnblogs.com/sbfhy/p/9410550.html

时间: 2024-11-29 08:19:15

2018 Multi-University Training Contest 3 1007 / hdu6325 Problem G. Interstellar Travel 凸包的相关文章

【单调栈】hdu6325 Problem G. Interstellar Travel

从后往前更新,维护一个递减单调栈(队列) 最近很多题都是单调栈... #define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<algorithm> #include<queue> #include<iostream> //#include<deque> using namespace std; const int maxn = 1e7 + 5; int n, m, k, P, Q, R,

hdu6325 Interstellar Travel 凸包变形

题目传送门 题目大意: 给出n个平面坐标,保证第一个点和第n个点y值为0,其余点的x坐标都在中间,要从 i 点走到 j 点的要求是 i 点的横坐标严格小于 j 的横坐标,并且消耗的能量是(xi * yj - xj * yi),要求消耗的能量最小(能量可以为负),并且字典序要求最小. 思路: 消耗能量的式子就是两个坐标的叉积,叉积的几何意义就是两个向量对应的平行四边形的面积,但是这个面积会有正负,如果向量 j 在向量 i 的顺时针方向,则这个面积是负的,如果我希望能量最小,那么就尽可能使向量是顺时

【2018 Multi-University Training Contest 2 1007】Naive Operations

[链接] 我是链接,点我呀:) [题意] 给你两个数组a,b; b数组是1..n的一个排列. 现在给你两种操作: add l,r将a[l..r]都加上1 query l,r 询问$∑^r_l\frac{ai}{bi} $ 其中a[i]/b[i]是下取整. n<=10^5 [题解] 很优秀的题 我们可以在线段树1中维护所有a[i]/b[i]的值 想一下何时我们才要让线段树1中的值改变? 必然是我们一直加a的值,让a[i]的值超过了b[i] 设让线段树中的值改变操作为操作x 那么操作x最多湖执行多少

2018 Multi-University Training Contest 3 1001 / hdu6319 Problem A. Ascending Rating 单调队列,思维

Problem A. Ascending Rating 题意: 给定一个序列a[1..n],对于所有长度为m的连续子区间,求出区间的最大值以及从左往右扫描该区间时a的最大值的变化次数. 1≤m≤n≤107. Shortest judge solution: 534 bytes 题解: 官方题解:按照r从m到n的顺序很难解决这个问题.考虑按照r从n到m的顺序倒着求出每个区间的答案.按照滑窗最大值的经典方法维护a的单调队列,那么队列中的元素个数就是最大值的变化次数.时间复杂度O(n). 最大值好算,

2018 Multi-University Training Contest 3 1003 / hdu6321 Problem C. Dynamic Graph Matching 状压dp

Problem C. Dynamic Graph Matching 题意: 给定一个n个点的无向图,m次加边或者删边操作.在每次操作后统计有多少个匹配包含k= 1,2,...,n2条边. 2≤n≤10,1≤m≤30000. Shortest judge solution: 770 bytes 题解: 设f[i][S]表示前i次操作之后,S集合的点已经匹配的方案数. 对于加边操作,显然f[i][S] =f[i?1][S] +f[i?1][S?u?v].i这一维可以省略,从大到小遍历S,f[S]+

2018 Nowcoder Multi-University Training Contest 2

Practice Link A. run 题意: 白云每次可以移动\(1\)米或者\(k\)米,询问移动的米数在\([L, R]\)范围内的方案数有多少. 思路: \(dp[i][2]\)表示到第\(i\)米,是通过\(1\)米的方式过来的还是\(k\)米的方式过来的,递推即可. 代码: #include <bits/stdc++.h> using namespace std; #define N 100010 const int p = 1e9 + 7; int f[N][2], g[N];

2018 Nowcoder Multi-University Training Contest 1

Practice Link J. Different Integers 题意: 给出\(n\)个数,每次询问\((l_i, r_i)\),表示\(a_1, \cdots, a_i, a_j, \cdots, a_n\)中有多少个不同的数. 思路: 先分别离线求出\(a_1, \cdots a_i\)以及\(a_j, \cdots, a_n\)中有多少个不同的数. 再考虑有多少个数既在\([1, i]\)中也在\([j, n]\)中,再离线做一次. 考虑一个数第一次出现的时候,那么这个数下一次出现

2018 Nowcoder Multi-University Training Contest 5

Practice Link A. gpa 题意: 有\(n\)门课程,每门课程的学分为\(s_i\),绩点为\(c_i\),要求最多删除\(k\)门课程,使得gpa最高. gpa计算方式如下: \[ \begin{eqnarray*} gpa = \frac{\sum s_ic_i}{\sum s_i} \end{eqnarray*} \] 思路: 首先删去的课程越多,gpa肯定不会变得更差. 所以我们肯定是删去\(k\)门课程. 考虑二分答案,check的时候要满足: \[ \begin{eq

UESTC_Infected Land 2015 UESTC Training for Search Algorithm &amp; String&lt;Problem G&gt;

G - Infected Land Time Limit: 6000/3000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status The earth is under an attack of a deadly virus. Luckily, prompt actions of the Ministry of Health against this emergency successfully