非加权双向图中最短路径和第二最短路径的区别

142 阅读8分钟

非加权双向图中最短路径和第二最短路径的区别

  • 最后更新: 2021年8月4日

给出一个包含N个节点和M条边的非加权双向图,用数组 arr[][2]表示。任务是找出从节点1N的最短路径和第二最短路径的长度差。

注意:该图是连接的,不包含多条边和自循环。(2<=N<=20)

例子。

**输入。**N = 4, M = 4, arr[M][2]={{1, 2}, {2, 3}, {3, 4}, {1, 4}}} 。
**输出。**2
解释。 最短路径是1->4,第二条最短路径是1->2->3->4。 因此,差值是2。

输入。 N = 6, M = 8, arr[M][2]={{1, 2}, {1, 3}, {2, 6}, {2, 3}, {2, 4}, {3, 4}, {3, 5}, {4, 6}} 。
**输出:**1

**办法。**其思路是深度优先搜索,找到所有可能的路径,并将其存储在向量中, 向量 进行排序,找出最短路径和第二短路径的区别。按照下面的步骤来解决这个问题。

  • 定义一个函数 dfs(vector<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。
  • 初始化一个二维向量 graph[][],有N行,用来存储从每个顶点连接的顶点。
  • 使用变量i [0, M]范围内迭代,并执行以下步骤。
  • 初始化一个大小为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 <bits/stdc++.h>
using namespace std;
// DFS function to find all possible paths.
void dfs(vector<vector<int> >& graph,int s,int e,
vector<int> v,int count, vector<int>& 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<vector<int> > graph(n, vector<int>());
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<int> v(n, 0);
// Vector to store the count of all possible paths.
vector<int> 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;
}

输出

1

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

高效的方法。利用第二条最短路径不可能包含所有与最短路径相同的边这一事实。将最短路径中的每条边逐一移除,继续寻找最短路径,那么其中一条必须是所需的第二最短路径。使用广度优先搜索来找到最佳解决方案。按照下面的步骤来解决这个问题。

  • 定义一个函数get_edges(int s, vector& edges, vector p)并执行以下步骤。
    • 如果s等于**-1,**则返回。
    • 调用函数**get_edges(p[s], edges, p)**来找到沿最短路径的所有边。
    • s的值推到 向量 edges[]
  • 定义一个函数**dist_helper(vector<vector > graph, vector& d, int v1, int v2, int N)**并执行以下步骤。
  • 定义一个函数dist(vector<ctor > graph, vector& d, vector &p, int N)并执行以下步骤
  • 初始化一个二维向量 graph[][],有N个行,用来存储从每个顶点连接的顶点。
  • 使用变量i [0, M]范围内进行迭代,并执行以下步骤。
  • 初始化大小为N的向量p[]d[],以跟踪父节点和路径的长度。
  • 调用函数**dist(graph, d, p, N)**来寻找最短路径的长度。
  • 初始化一个向量 **distances[]**来存储所有可能路径的长度。
  • **d[N-1]**的值推到 向量 distances[]
  • 初始化一个向量**edges[]**以获得沿最短路径的所有边。
  • 调用函数**get_edges(N-1, edges, p)**来寻找沿最短路径的所有边。
  • 使用变量i在**[0, edges.size()-1]**范围内进行迭代,并执行以下步骤。
    • 调用函数**dist_helper(graph, d, edges[i], edges[i+1], N)**来找到沿最短路径的所有边。
    • **d[N-1]**的值推到 向量 distances[]
  • 向量distances**[**]按升序排序。
  • 如果向量 distances[]的大小大于1,那么返回distances[1]-distances[0]的值,否则返回0作为答案。

下面是上述方法的实现。

C++

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to get all the edges in
// the shortest path
void get_edges(int s, vector<int>& edges, vector<int> 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<vector<int> > graph, vector<int>& d,
int v1,int v2,int n)
{
// Vector to mark the nodes visited
vector<int> v(n, 0);
// For BFS
queue<pair<int,int> > 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<vector<int> > graph, vector<int>& d,
vector<int>& p,int n)
{
// Vector to mark the nodes visited
vector<int> v(n, 0);
// For BFS
queue<pair<int,int> > 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<vector<int> > graph(n, vector<int>());
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<int> p(n, -1);
vector<int> d(n, 1e9);
// Calculate the shortest path
dist(graph, d, p, n);
// Vector to store the lengths
// of possible paths
vector<int> distances;
distances.push_back(d[n - 1]);
vector<int> 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概念。 DSA自学课程以适合学生的价格掌握所有重要的DSA概念,并成为行业的准备者。 要完成从学习语言到DS Algo以及更多的准备工作,请参考 完整的面试准备课程.

如果你想参加专家的现场课程 ,请参考 面向在职人士的DSA现场课程面向学生的竞争性编程直播.

我的个人笔记 箭头_下降_上升

保存