zoukankan      html  css  js  c++  java
  • 2014百度之星复赛解题报告复赛:Race

    Race
    时间限制:10s  内存限制:64MB

    问题描述
    度度熊最近参加了一场劲跑比赛,但是这个劲跑比赛的规则比较特殊。比赛方预先在地上画了一些横线和竖线(可以认为这些线为无限长的直线),要求选手从指定的位置出发,在最短时间内按照规定的顺序经过所有的直线(只要到达直线上的任意一点即为经过)。为了帮助度度熊获胜,你能为他规划一条最短的线路吗?

    输入
    第一行为T,表示输入数据组数。
    下面T组数据。每组数据中:
    第一行为一个整数n,表示有n条直线。接下来n行,每行包含两个整数,表示一条直线。如果直线为竖线,则第一个整数为0,第二个整数为直线的横坐标x。如果直线为横线,则第一个整数为1,第二个整数为直线的纵坐标y。度度熊将从平面的原点出发。

    输出
    对第i组数据,输出
    Case #i:
    然后输出一个实数,表示从原点出发按输入顺序经过所有直线的最短路径的长度。保留到小数点后3位。

    限制条件
    1<=T<=10
    1<=n<=10^6
    -500<=x,y<=500

    样例输入
    1
    3
    0 1
    1 1
    0 2

    样例输出
    Case #1:
    2.236

    提示
    度度熊需要按照规定的顺序经过所有的直线。如果度度熊不按照顺序经过直线,那么提前经过的直线是不算数的。例如,假设度度熊需要按顺序经过直线1和直线2,那么如果度度熊在经过直线2之前经过了直线1,这是不算数的,度度熊仍然需要在经过直线2后再次经过直线1。但是度度熊可以经过直线1和直线2的交叉点而同时都算数。

    解题报告:
    首先对横线和竖线的坐标分别做镜像翻装,使它们的坐标分别都是单调(非严格)递增的,并且相邻的横线和相邻的竖线的距离跟原始坐标的距离保持一致。这可以在线性时间内完成,并且不影响答案。然后按照顺序扫描所有直线,维护从原点出发的两条移动路径。一条移动路径尽可能往左走,一条移动路径尽可能往右走,但都保持最短路并且满足规定的直线到达顺序。这两条移动路径分别是上凸曲线和下凸曲线,每扫描到方向不同的两条直线时就根据交叉点更新其中一条移动路径。扫描到最后一条直线时就可以算出最短的移动路径长度了。


    解题代码:
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    
    const int MAX_N = 1000000;
    
    struct Point {
        int x, y;
        Point() {
            x = 0;
            y = 0;
        }
        Point(int x_, int y_) {
            x = x_;
            y = y_;
        }
    };
    
    int n;
    int dirs[MAX_N];
    int lines[MAX_N];
    
    inline long long cross_product(Point a, Point b) {
        return (long long)a.x * b.y - (long long)b.x * a.y;
    }
    
    inline long long cross_product(Point a, Point b, Point c) {
        return cross_product(Point(b.x - a.x, b.y - a.y), Point(c.x - a.x, c.y - a.y));
    }
    
    inline double distance(Point a, Point b) {
        return sqrt(double(a.x - b.x) * (a.x - b.x) + double(a.y - b.y) * (a.y - b.y));
    }
    
    void preprocess_lines() {
        int lastlines[2] = {0, 0};
        int lastrawlines[2] = {0, 0};
        for (int i = 0; i < n; i++) {
            int dir = dirs[i];
            int rawline = lines[i];
            lines[i] = lastlines[dir] + abs(rawline - lastrawlines[dir]);
            lastrawlines[dir] = rawline;
            lastlines[dir] = lines[i];
        }
    }
    
    double solve() {
        static Point lstack[MAX_N];
        static Point rstack[MAX_N];
        int lhead, ltail, rhead, rtail;
        lhead = ltail = rhead = rtail = 0;
        lstack[ltail++] = Point(0, 0);
        rstack[rtail++] = Point(0, 0);
        double result = 0;
    
        for (int i = 1; i < n; i++) {
            if (dirs[i] == 1 && dirs[i - 1] == 0) {
                Point pos(lines[i - 1], lines[i]);
                while (lhead + 2 <= ltail && cross_product(lstack[ltail - 2], lstack[ltail - 1], pos) <= 0) {
                    ltail--;
                }
                lstack[ltail++] = pos;
                while (lhead + 2 == ltail && rhead + 2 <= rtail && cross_product(lstack[lhead], pos, rstack[rhead + 1]) >= 0) {
                    result += ::distance(lstack[lhead], rstack[++rhead]);
                    lstack[lhead] = rstack[rhead];
                }
            }
            if (dirs[i] == 0 && dirs[i - 1] == 1) {
                Point pos(lines[i], lines[i - 1]);
                while (rhead + 2 <= rtail && cross_product(rstack[rtail - 2], rstack[rtail - 1], pos) >= 0) {
                    rtail--;
                }
                rstack[rtail++] = pos;
                while (rhead + 2 == rtail && lhead + 2 <= ltail && cross_product(rstack[rhead], pos, lstack[lhead + 1]) <= 0) {
                    result += ::distance(rstack[rhead], lstack[++lhead]);
                    rstack[rhead] = lstack[lhead];
                }
            }
        }
    
        if (dirs[n - 1] == 1) {
            for (int i = lhead; i + 1 < ltail; i++) {
                result += ::distance(lstack[i], lstack[i + 1]);
            }
            result += lines[n - 1] - lstack[ltail - 1].y;
        }
        if (dirs[n - 1] == 0) {
            for (int i = rhead; i + 1 < rtail; i++) {
                result += ::distance(rstack[i], rstack[i + 1]);
            }
            result += lines[n - 1] - rstack[rtail - 1].x;
        }
    
        return result;
    }
    
    int main() {
        int TT, NN;
        scanf("%d", &NN);
        for (TT = 1; TT <= NN; TT++) {
            scanf("%d", &n);
            for (int i = 0; i < n; i++) {
                scanf("%d%d", &dirs[i], &lines[i]);
            }
            preprocess_lines();
            double ans = solve();
            printf("Case #%d:
    ", TT);
            printf("%.3f
    ", ans);
        }
    
        return 0;
    }

  • 相关阅读:
    DataGridView 中的复选框DataGridViewCheckBoxColumn 添加验证
    DataGridView删除行 提示 索引-1没有值 索引0没有值 等 解决办法
    convert mov mp4 to jpg
    拼图
    remove ad of chrome how to block ad of newssysstem.net
    redis3常用命令
    python_爬虫总结
    boot_自定义异常
    简答题总结
    springmvc_文件上传
  • 原文地址:https://www.cnblogs.com/hosealeo/p/4190490.html
Copyright © 2011-2022 走看看