zoukankan      html  css  js  c++  java
  • 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,纵坐标 Yi >=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, " 
    "[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;
    }
    
  • 相关阅读:
    SqlServer2008启动不了的问题
    .exe 不包含适合入口点的静态“Main”方法
    两种常用的序列化
    异或运算^
    SqlServer数据库实现C#中的split功能
    遍历电脑下面所有文件--递归
    ExecuteNonQuery引发了System.ArgumentException类型异常
    JQuery属性过滤(转)
    SQL SERVER 执行远端数据库的SQL命令
    马云:做一个静静的观察者 能学到更多
  • 原文地址:https://www.cnblogs.com/sbfhy/p/9410550.html
Copyright © 2011-2022 走看看