349删除路径后的最短路问题--Floyd-Warshall 算法|豆包MarsCode AI刷题

56 阅读6分钟

349删除路径后的最短路问题--Floyd-Warshall 算法|豆包MarsCode AI刷题

问题描述

小F正在探索一个有n个点的地图,其中每个点都有对应的二维坐标 (𝑥𝑖,𝑦𝑖)。起点是第s个点,终点是第t个点,原本所有点之间都有一条线段,表示可以通行,并且长度为欧几里得距离。但是由于某些意外,起点s和终点t之间的直接通行路径被删除了。小F希望你帮忙计算从s到t的最短路径,允许经过其他点,但不能直接通过删除的那条线。

需要注意的是,点 i,j 之间的欧几里得距离计算公式为:

sqrt((x_i - x_j)^2 + (y_i - y_j)^2)

你需要输出从起点s到终点t的最短距离,结果需要四舍五入到小数点后两位。


测试样例

样例1:

输入:n = 5 ,s = 1 ,t = 5,x = [17253, 25501, 28676, 30711, 18651],y = [15901, 15698, 32041, 11015, 9733]
输出:'17333.65'

样例2:

输入:n = 4 ,s = 2 ,t = 4,x = [5000, 12000, 8000, 14000],y = [3000, 9000, 1000, 4000]
输出:'15652.48'

样例3:

输入:n = 6 ,s = 3 ,t = 6,x = [20000, 22000, 24000, 26000, 28000, 30000],y = [15000, 13000, 11000, 17000, 19000, 21000]
输出:'11772.70'

要解决这个问题,我们可以使用' Floyd-Warshall '算法来计算所有点对之间的最短路径,然后忽略起点和终点之间的直接路径。Floyd-Warshall 算法是一个动态规划算法,可以在 O(n^3) 的时间复杂度内计算加权图中所有节点对之间的最短路径。

Floyd-Warshall 算法是一种用于计算加权图中所有节点对之间最短路径的动态规划算法。它适用于具有正权重和负权重(但不允许有负权重环)的图。该算法的核心思想是通过逐步考虑图中的每个节点作为中间节点,来更新任意两个节点之间的最短路径。

Floyd-Warshall 算法的基本步骤:

  1. 初始化距离矩阵

    • 创建一个二维数组 dist,其中 dist[i][j] 表示从节点 i 到节点 j 的最短路径的权重。
    • 如果节点 i 和节点 j 之间有直接路径,则 dist[i][j] 被初始化为该路径的权重;否则,它被初始化为无穷大(表示不存在直接路径)。
    • 对于每个节点 i,将 dist[i][i] 初始化为 0,因为从节点到其自身的路径权重为 0。
  2. 更新距离矩阵

    • 对于图中的每个节点 k(作为中间节点),更新 dist 矩阵。
    • 对于每对节点 (i, j),检查通过中间节点 k 是否可以缩短从 i 到 j 的路径。
    • 如果 dist[i][k] 和 dist[k][j] 都不是无穷大,并且 dist[i][k] + dist[k][j] < dist[i][j],则更新 dist[i][j] 为 dist[i][k] + dist[k][j]
  3. 输出结果

    • 在更新完所有节点后,dist 矩阵将包含从图中任意两个节点之间的最短路径权重。

Floyd-Warshall 算法的时间复杂度为 O(V^3),其中 V 是图中的节点数。这是因为算法需要三层嵌套循环来遍历所有节点对和中间节点。


Dijkstra算法实现步骤

  1. 初始化:将源点加入到集合U中,并设置源点到自身的距离为0,源点到其他顶点的距离为无穷大(或一个足够大的数)。
  2. 选择:从集合T中选择到源点路径长度最短的顶点u。
  3. 更新:将顶点u加入到集合U中,并更新集合T中剩余顶点的当前最短路径值。对于集合T中的每个顶点v,如果通过顶点u到达v的路径比当前记录的最短路径更短,则更新v的最短路径值为该路径的长度。
  4. 重复:重复步骤2和步骤3,直到集合T中的顶点全部加入到集合U中。

解题

  1. 创建一个二维距离矩阵 dist,其中 dist[i][j] 表示从点 i 到点 j 的最短距离。如果两点之间没有直接路径,则初始化为无穷大(例如,使用 INT_MAX 或 1e9)。
  2. 初始化 dist 矩阵,将每个点到自身的距离设为 0,并根据输入的坐标计算每对点之间的欧几里得距离。
  3. 将起点和终点之间的直接路径距离设为无穷大,以模拟这条路径被删除的情况。
  4. 使用 Floyd-Warshall 算法更新 dist 矩阵,计算所有点对之间的最短路径。
  5. 输出从起点 s 到终点 t 的最短路径距离,并保留两位小数。
#include <iostream>
#include <vector>
#include <cmath>
#include <iomanip>
#include <limits>

using namespace std;

string solution(int n, int s, int t, vector<int> x, vector<int> y) {
    const double INF = 1e9;
    vector<vector<double>> dist(n, vector<double>(n, INF));

    // Calculate Euclidean distances
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i == j) {
                dist[i][j] = 0;
            } else {
                double dx = x[i] - x[j];
                double dy = y[i] - y[j];
                dist[i][j] = sqrt(dx * dx + dy * dy);
            }
        }
    }

    // Set the direct path from s to t to infinity
    dist[s - 1][t - 1] = INF;

    // Floyd-Warshall algorithm
    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }

    // Output the result rounded to two decimal places
    ostringstream oss;
    oss << fixed << setprecision(2) << dist[s - 1][t - 1];
    return oss.str();
}

int main() {
    cout << boolalpha;
    cout << (solution(5, 1, 5, {17253, 25501, 28676, 30711, 18651}, {15901, 15698, 32041, 11015, 9733}) == "17333.65") << endl;
    cout << (solution(4, 2, 4, {5000, 12000, 8000, 14000}, {3000, 9000, 1000, 4000}) == "15652.48") << endl;
    cout << (solution(6, 3, 6, {20000, 22000, 24000, 26000, 28000, 30000}, {15000, 13000, 11000, 17000, 19000, 21000}) == "11772.70") << endl;
    return 0;
}