Intelligent Robot

Amber0130發表於2020-10-26

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述

Given a maze of size n × m n\times m n×m, whose lower-left corner is ( 0 , 0 ) (0, 0) (0,0) while upper-right corner is ( n , m ) (n, m) (n,m) . And there are k k k segment walls in the maze. One cannot cross the walls but can touch them or walk along them. Now a MI robot is assigned to go from ( X 1 , Y 1 ) (X_1, Y_1) (X1,Y1) to ( X 2 , Y 2 ) (X_2, Y_2) (X2,Y2), as an intelligent robot, MI robot will automatically determine the shortest valid path and go along it. Print the length of the shortest valid path between ( X 1 , Y 1 ) (X_1, Y_1) (X1,Y1) and ( X 2 , Y 2 ) (X_2, Y_2) (X2,Y2)

輸入描述

The first line contains three integers n , m , k n,m,k n,m,k( 1 ≤ n , m ≤ 10000 , 0 ≤ k ≤ 300 1\le n,m \le 10000, 0\le k\le 300 1n,m10000,0k300, denoting the size of the maze and the number of walls respectively.

Following k k k lines each contains four integers x 1 , y 1 , x 2 , y 2   ( 1 ≤ x 1 , x 2 < n , 1 ≤ y 1 , y 2 < m ) x_1,y_1,x_2,y_2~(1\le x_1,x_2 < n, 1\le y_1,y_2 < m) x1,y1,x2,y2 (1x1,x2<n,1y1,y2<m), denoting a segment wall ( x 1 , y 1 ) − ( x 2 , y 2 ) (x_1,y_1) - (x_2,y_2) (x1,y1)(x2,y2)

The next line contains four integers X 1 , Y 1 , X 2 , Y 2 ( 0 ≤ X 1 , X 2 ≤ n , 0 ≤ Y 1 , Y 2 ≤ m ) X_1,Y_1,X_2,Y_2(0\le X_1,X_2 \le n, 0\le Y_1,Y_2\le m) X1,Y1,X2,Y2(0X1,X2n,0Y1,Y2m), denoting the two given points.

It’s guaranteed that no two segment walls share common points, and that no segment wall covers ( X 1 , Y 1 ) (X_1, Y_1) (X1,Y1) or ( X 2 , Y 2 ) (X_2, Y_2) (X2,Y2) and that either X 1 ≠ X 2 X_1 \neq X_2 X1=X2 or Y 1 ≠ Y 2 Y_1 \neq Y_2 Y1=Y2

輸出描述

Only one line containing a real number with four decimal places after the decimal point, denoting the answer.

It’s guaranteed that the fifth decimal place after the decimal point is neither 4 4 4 nor 5 5 5.

示例1

輸入

6 3 2
1 1 3 1
2 2 5 2
3 0 3 3

輸出

3.8284

說明

One possible way is ( 3 , 0 ) → ( 3 , 1 ) → ( 2 , 2 ) → ( 3 , 3 ) (3, 0) \rightarrow (3, 1) \rightarrow (2, 2) \rightarrow (3, 3) (3,0)(3,1)(2,2)(3,3), and the exact answer is 2 2 + 1 2\sqrt{2} + 1 22 +1

思路

先將每一條線段兩個端點連邊,權值為線段的長度
再將任意兩個點連邊(前提是這條線段與其他的k條線段沒有交點),權值為這兩個點的距離。
D i j s k r a Dijskra Dijskra 從起始點到終點跑最短路。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 8e5 + 10;

struct Point {
    int x, y;

    Point(int x = 0, int y = 0) : x(x), y(y) {};

    Point operator-(const Point &oth) const {
        return Point(x - oth.x, y - oth.y);
    }

    ll operator*(const Point &oth) const {
        return 1ll * x * oth.y - 1ll * y * oth.x;
    }
};

int sqr(int x) {
    return x * x;
}

struct Line {
    Point a, b;

    double dis() const {
        return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
    }
} l[310];

int n;
int t;
struct edge {
    int v, nxt;
    double w;
} e[maxn];
int head[1010];
vector<Point> a;

void add(int u, int v, double w) {
    t++;
    e[t].v = v;
    e[t].w = w;
    e[t].nxt = head[u];
    head[u] = t;
}

double dis[1010];
int vis[1010], k;

void Dijskra(int s, int t) {
    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> q;
    q.push({0, 0});
    for (int i = s + 1; i <= t; i++) {
        dis[i] = 1e10;
    }
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w) {
                dis[v] = dis[u] + e[i].w;
                q.push({dis[v], v});
            }
        }
    }
}

bool check(Line x) {
    for (int i = 1; i <= k; i++) {
        Point AC = l[i].b - x.a;
        Point AD = l[i].a - x.a;
        Point AB = x.b - x.a;
        Point CA = x.a - l[i].b;
        Point CB = x.b - l[i].b;
        Point CD = l[i].a - l[i].b;
        if ((AC * AB) * (AD * AB) < 0 && (CA * CD) * (CB * CD) < 0) {
            return 1;
        }
    }
    return 0;
}

int main() {
    //freopen("1.txt", "r", stdin);
    int n, m;
    scanf("%d%d%d", &n, &m, &k);
    Point st, en;
    for (int i = 1; i <= k; i++) {
        scanf("%d%d%d%d", &l[i].a.x, &l[i].a.y, &l[i].b.x, &l[i].b.y);
    }
    scanf("%d%d", &st.x, &st.y);
    scanf("%d%d", &en.x, &en.y);
    a.push_back(st);
    for (int i = 1; i <= k; i++) {
        a.push_back(l[i].a);
        a.push_back(l[i].b);
        add(a.size() - 2, a.size() - 1, l[i].dis());
    }
    a.push_back(en);
    int sz = a.size();
    for (int i = 0; i < sz; i++) {
        for (int j = i + 1; j < sz; j++) {
            if (!check(Line{a[i], a[j]})) {
                double len = Line{a[i], a[j]}.dis();
                add(i, j, len);
                add(j, i, len);
            }
        }
    }
    Dijskra(0, sz - 1);
    printf("%.4lf\n", dis[sz - 1]);
    return 0;
}

相關文章