📜  未加权双向图中最短路径和第二最短路径之间的差异

📅  最后修改于: 2021-10-25 04:51:07             🧑  作者: Mango

给定一个包含N 个节点和M 个边的未加权双向图,由数组arr[][2] 表示。任务是找出从节点1N 的最短路径和第二最短路径的长度差。如果第二条最短路径不存在,则打印0

例子:

方法:思想是深度优先搜索找到所有可能的路径并将它们存储在向量中并对向量进行排序并找到最短路径和第二最短路径之间的差异。请按照以下步骤解决问题:

  • 定义一个函数dfs(vector >& graph, int s, int e, vector vis, int count, vector& dp)并执行以下步骤:
    • 如果s等于e ,则表示当前路径是可能的路径之一,将count的值压入向量dp[]并返回。
    • 使用变量i迭代范围[0, graph[s]]并执行以下步骤:
      • 如果vis[i]不等于1,则将vis[i]的值设置为1并调用函数dfs(graph, i, e, vis, count+1, dp)寻找其他可能的路径并设置vis[0] 的值再次回到0。
  • N行初始化一个二维向量图 [][]来存储从每个顶点连接的顶点。
  • 使用变量i在范围[0, M] 上迭代并执行以下步骤:
    • b-1的值推入第a-1 行的矢量图[][]
    • 将向量a-1的值推入b-1行中的矢量图[][]
  • 初始化大小为N的向量vis[]以跟踪访问过的节点。
  • 初始化一个向量dp[]来存储所有可能路径的长度。
  • 调用函数dfs(graph, 0, N-1, vis, 0, dp)以查找所有可能的路径并将它们存储在向量dp[] 中
  • 按升序对向量dp[]进行排序。
  • 如果向量dp[]的大小大于1,则返回值dp[1]-dp[0]否则返回0作为答案。

下面是上述方法的实现。

C++14
// C++ program for the above approach
#include 
using namespace std;
 
// DFS function to find all possible paths.
void dfs(vector >& graph, int s, int e,
         vector v, int count, vector& dp)
{
    if (s == e) {
        // Push the number of nodes required for
        // one of the possible paths
        dp.push_back(count);
        return;
    }
    for (auto i : graph[s]) {
        if (v[i] != 1) {
 
            // Mark the node as visited and
            // call the function to search for
            // possible paths and unmark the node.
            v[i] = 1;
            dfs(graph, i, e, v, count + 1, dp);
            v[i] = 0;
        }
    }
}
 
// Function to find the difference between the
// shortest and second shortest path
void findDifference(int n, int m, int arr[][2])
{
    // Construct the graph
    vector > graph(n, vector());
    for (int i = 0; i < m; i++) {
        int a, b;
        a = arr[i][0];
        b = arr[i][1];
        graph[a - 1].push_back(b - 1);
        graph[b - 1].push_back(a - 1);
    }
 
    // Vector to mark the nodes as visited or not.
    vector v(n, 0);
 
    // Vector to store the count of all possible paths.
    vector dp;
 
    // Mark the starting node as visited.
    v[0] = 1;
 
    // Function to find all possible paths.
    dfs(graph, 0, n - 1, v, 0, dp);
 
    // Sort the vector
    sort(dp.begin(), dp.end());
 
    // Print the difference
    if (dp.size() != 1)
        cout << dp[1] - dp[0];
    else
        cout << 0;
}
 
// Driver Code
int main()
{
    int n, m;
    n = 6;
    m = 8;
    int arr[m][2]
        = { { 1, 2 }, { 1, 3 },
            { 2, 6 }, { 2, 3 },
            { 2, 4 }, { 3, 4 },
            { 3, 5 }, { 4, 6 } };
 
    findDifference(n, m, arr);
 
    return 0;
}


Javascript


C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to get all the edges in
// the shortest path
void get_edges(int s, vector& edges, vector p)
{
    if (s == -1)
        return;
    get_edges(p[s], edges, p);
    edges.push_back(s);
}
 
// Calculate the shortest distance
// after removing an edge between
// v1 and v2
void dist_helper(vector > graph, vector& d,
                 int v1, int v2, int n)
{
    // Vector to mark the nodes visited
    vector v(n, 0);
 
    // For BFS
    queue > q;
    q.push(make_pair(0, 0));
    v[0] = 1;
 
    // Iterate over the range
    while (!q.empty()) {
        auto a = q.front();
        q.pop();
        for (int i : graph[a.first]) {
            if ((i == v1 && a.first == v2)
                || (i == v2 && a.first == v1))
                continue;
            if (v[i] == 0) {
                d[i] = 1 + a.second;
                v[i] = 1;
                q.push(make_pair(i, d[i]));
            }
        }
    }
}
 
// Calculates the shortest distances and
// maintain a parent array
void dist(vector > graph, vector& d,
          vector& p, int n)
{
    // Vector to mark the nodes visited
    vector v(n, 0);
 
    // For BFS
    queue > q;
    q.push(make_pair(0, 0));
    v[0] = 1;
 
    // Iterate over the range
    while (!q.empty()) {
        auto a = q.front();
        q.pop();
        for (int i : graph[a.first]) {
            if (v[i] == 0) {
                p[i] = a.first;
                d[i] = 1 + a.second;
                v[i] = 1;
                q.push(make_pair(i, d[i]));
            }
        }
    }
}
 
// Function to find the difference between the
// shortest and second shortest path
void findDifference(int n, int m, int arr[][2])
{
 
    // Initializing and constructing the graph
    vector > graph(n, vector());
    for (int i = 0; i < m; i++) {
        int a, b;
        a = arr[i][0];
        b = arr[i][1];
        graph[a - 1].push_back(b - 1);
        graph[b - 1].push_back(a - 1);
    }
 
    // Initializing the arrays
    vector p(n, -1);
    vector d(n, 1e9);
 
    // Calculate the shortest path
    dist(graph, d, p, n);
 
    // Vector to store the lengths
    // of possible paths
    vector distances;
    distances.push_back(d[n - 1]);
 
    vector edges;
 
    // Get all the edges along the shortest path
    get_edges(n - 1, edges, p);
 
    // Iterate over the range
    for (int i = 0; i + 1 < edges.size(); i++) {
        // Calculate shortest distance after
        // removing the edge
        dist_helper(graph, d, edges[i], edges[i + 1], n);
        distances.push_back(d[n - 1]);
    }
 
    // Sort the paths in ascending order
    sort(distances.begin(), distances.end());
    if (distances.size() == 1)
        cout << 0 << endl;
    else
        cout << distances[1] - distances[0] << endl;
}
 
// Driver Code
int main()
{
    int n, m;
    n = 6;
    m = 8;
    int arr[m][2]
        = { { 1, 2 }, { 1, 3 },
            { 2, 6 }, { 2, 3 },
            { 2, 4 }, { 3, 4 },
            { 3, 5 }, { 4, 6 } };
 
    findDifference(n, m, arr);
 
    return 0;
}


输出
1

时间复杂度: O(2^N)
辅助空间: O(N)

高效方法:利用第二最短路径不能包含与最短路径相同的所有边的事实。一次删除最短路径的每条边并继续寻找最短路径,那么其中之一必须是所需的第二最短路径。使用广度优先搜索以最佳方式找到解决方案。请按照以下步骤解决问题:

  • 定义一个函数get_edges(int s, vector&edges, vector p)并执行以下步骤:
    • 如果s等于-1,则返回。
    • 调用函数get_edges(p[s],edges,p)以找到沿最短路径的所有边。
    • 在向量edges[] 中推送s的值
  • 定义一个函数dist_helper(vector > graph, vector& d, int v1, int v2, int N)并执行以下步骤:
    • 初始化向量vis[]以跟踪访问过的节点。
    • 初始化成对队列q[]以进行广度优先搜索并找到路径。
    • 将一对{0, 0}加入对q[]的队列中
    • vis[0]的值标记为1(visited)
    • 在 while 循环中迭代,直到对q[]的队列不为空。
      • 将变量a初始化为q[]对队列的前端,并将元素从q[]对队列中出列
      • 使用变量i迭代范围[0, graph[a.first]]并执行以下步骤:
        • 如果i等于v1a.first等于v2i等于v2a.first等于v1,则继续。
        • 如果vis[i]等于0,则将d[i]的值设置为1+a.second,将 p[i] 设置a.first并将vis[i] 设置1并将{i, d[ i]}进入对q[]的队列
  • 定义一个函数dist(vector > graph, vector& d, vector &p, int N)并执行以下步骤:
    • 初始化向量vis[]以跟踪访问过的节点。
    • 初始化成对队列q[]以进行广度优先搜索并找到路径。
    • 将一对{0, 0}加入对q[]的队列中
    • vis[0]的值标记为1(visited)
    • 在 while 循环中迭代,直到对q[]的队列不为空。
      • 将变量a初始化为q[]对队列的前端,并从q[]对队列中取出一个元素
      • 使用变量i迭代范围[0, graph[a.first]]并执行以下步骤:
        • 如果vis[i]等于0,则将d[i]的值设置为1+a.second并将vis[i] 设置1并将{i, d[i]}对加入对q的队列[]。
  • N行初始化一个二维向量图 [][]来存储从每个顶点连接的顶点。
  • 使用变量i在范围[0, M] 上迭代并执行以下步骤:
    • b-1的值推入第a-1 行的矢量图[][]
    • a-1的值推入第b-1行的矢量图[][]
  • 初始化大小为N的向量p[]d[]以跟踪父节点和路径的长度。
  • 调用函数dist(graph, d, p, N)找到最短路径的长度。
  • 初始化一个向量distances[]来存储所有可能路径的长度。
  • 在向量distances[] 中推送d[N-1]的值
  • 初始化一个向量edges[]以获取沿最短路径的所有边。
  • 调用函数get_edges(N-1,edges, p)以找到沿最短路径的所有边。
  • 使用变量i迭代范围[0,edge.size()-1]并执行以下步骤:
    • 调用函数dist_helper(graph, d,edges[i],edges[i+1],N)找到沿最短路径的所有边。
    • 在向量distances[] 中推送d[N-1]的值
  • 按升序对向量距离 []进行排序。
  • 如果向量distances[]的大小大于1,则返回值distances[1]-distances[0]否则返回0作为答案。

下面是上述方法的实现。

C++

// C++ program for the above approach
#include 
using namespace std;
 
// Function to get all the edges in
// the shortest path
void get_edges(int s, vector& edges, vector p)
{
    if (s == -1)
        return;
    get_edges(p[s], edges, p);
    edges.push_back(s);
}
 
// Calculate the shortest distance
// after removing an edge between
// v1 and v2
void dist_helper(vector > graph, vector& d,
                 int v1, int v2, int n)
{
    // Vector to mark the nodes visited
    vector v(n, 0);
 
    // For BFS
    queue > q;
    q.push(make_pair(0, 0));
    v[0] = 1;
 
    // Iterate over the range
    while (!q.empty()) {
        auto a = q.front();
        q.pop();
        for (int i : graph[a.first]) {
            if ((i == v1 && a.first == v2)
                || (i == v2 && a.first == v1))
                continue;
            if (v[i] == 0) {
                d[i] = 1 + a.second;
                v[i] = 1;
                q.push(make_pair(i, d[i]));
            }
        }
    }
}
 
// Calculates the shortest distances and
// maintain a parent array
void dist(vector > graph, vector& d,
          vector& p, int n)
{
    // Vector to mark the nodes visited
    vector v(n, 0);
 
    // For BFS
    queue > q;
    q.push(make_pair(0, 0));
    v[0] = 1;
 
    // Iterate over the range
    while (!q.empty()) {
        auto a = q.front();
        q.pop();
        for (int i : graph[a.first]) {
            if (v[i] == 0) {
                p[i] = a.first;
                d[i] = 1 + a.second;
                v[i] = 1;
                q.push(make_pair(i, d[i]));
            }
        }
    }
}
 
// Function to find the difference between the
// shortest and second shortest path
void findDifference(int n, int m, int arr[][2])
{
 
    // Initializing and constructing the graph
    vector > graph(n, vector());
    for (int i = 0; i < m; i++) {
        int a, b;
        a = arr[i][0];
        b = arr[i][1];
        graph[a - 1].push_back(b - 1);
        graph[b - 1].push_back(a - 1);
    }
 
    // Initializing the arrays
    vector p(n, -1);
    vector d(n, 1e9);
 
    // Calculate the shortest path
    dist(graph, d, p, n);
 
    // Vector to store the lengths
    // of possible paths
    vector distances;
    distances.push_back(d[n - 1]);
 
    vector edges;
 
    // Get all the edges along the shortest path
    get_edges(n - 1, edges, p);
 
    // Iterate over the range
    for (int i = 0; i + 1 < edges.size(); i++) {
        // Calculate shortest distance after
        // removing the edge
        dist_helper(graph, d, edges[i], edges[i + 1], n);
        distances.push_back(d[n - 1]);
    }
 
    // Sort the paths in ascending order
    sort(distances.begin(), distances.end());
    if (distances.size() == 1)
        cout << 0 << endl;
    else
        cout << distances[1] - distances[0] << endl;
}
 
// Driver Code
int main()
{
    int n, m;
    n = 6;
    m = 8;
    int arr[m][2]
        = { { 1, 2 }, { 1, 3 },
            { 2, 6 }, { 2, 3 },
            { 2, 4 }, { 3, 4 },
            { 3, 5 }, { 4, 6 } };
 
    findDifference(n, m, arr);
 
    return 0;
}

输出
1

时间复杂度: O(N*M)
辅助空间: O(N)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程