📜  Dijkstra 的最短路径和最小边

📅  最后修改于: 2021-10-26 05:34:49             🧑  作者: Mango

先决条件: Dijkstra 最短路径算法
给定一个邻接矩阵图,表示给定图中节点之间的路径。任务是找到具有最少边的最短路径,即如果有多个具有相同成本的短路径,则选择具有最少边数的路径。
考虑下图:

从顶点0到顶点3有两条路径,权重为 12:

  1. 0 -> 1 -> 2 -> 3
  2. 0 -> 4 -> 3

因为,Dijkstra 算法是一种贪心算法,它在每次迭代中寻找最小加权顶点,所以原始 Dijkstra 算法将输出第一条路径,但结果应该是第二条路径,因为它包含最少的边数。
例子:

方法:该算法的思想是使用原始的 Dijkstra 算法,但也通过一个数组来跟踪路径的长度,该数组存储从源顶点开始的路径长度,因此如果我们找到一条较短的路径同样的重量,那我们就拿走。
让我们按照上面的示例迭代迭代:
考虑我们想要找到从顶点 0 到顶点 3 的最短路径
初始状态:与往常一样,所有顶点的距离和父节点分别为InfinityNILL
但是现在,我们还有一个名为pathlength[] 的数组,它存储从源顶点到所有顶点的路径长度。
最初,我们将pathlength[] 的所有元素设置为0

第一次迭代:首先我们寻找包含最小距离的顶点,即顶点0 ,如上图所示。
然后,我们遍历所有没有变黑的邻居,即14 。由于顶点14的距离是无穷大,因此我们将它们的权重分别减少到110 。更新父节点,并将每个顶点( 14 )的pathlength[]设置为1,因为它们可以从源顶点通过 1 条边到达。
之后,我们像原始 Dijkstra 算法一样将顶点变黑。

第二次迭代:我们继续寻找包含最小距离的非黑色顶点,即顶点1 ,然后我们将其邻居的权重减少到1 + 4 = 5并像原始 Dijkstra 算法一样更新其父节点,并设置它的pathlength[]2 ,因为它离源顶点有两条边。
最后,我们将顶点1变黑。

第三次迭代:同样,包含最小距离的非黑化顶点是顶点2 ,因此我们更新非黑化邻居。它有一个未变黑的邻居,即顶点3 。因此,我们将其权重从Infinity更新为5 + 7 = 12,然后将其父节点设置为2 ,并将其路径长度 []设置为3,因为它与源顶点有 3 条边。
最后,我们将顶点2变黑。

第四次迭代:在本次迭代中,算法的行为与原始 Dijkstra 算法不同。我们寻找包含最小距离为4的非黑化顶点。因为,从源顶点到顶点3 的距离是12 (0->1->2->3) 并且顶点4加上边(4, 3) 的距离是12 ,这意味着我们刚刚找到了一个新的从具有相同权重的源顶点到顶点3 的路径。然后,我们检查新路径是否比现有路径更短(在边上),并选择具有最小边的路径。
最后,我们将顶点4变黑。

由于V-1顶点被黑化,算法结束。
下面是上述方法的实现:

C++
// C++ program to find the shortest path
// with minimum edges in a graph
#include 
using namespace std;
#define INFINITY 9999
#define n 5
#define s 0
#define d 3
#define NILL -1
int MinDistance(int*, int*);
void PrintPath(int*, int);
 
// Function to find the shortest path
// with minimum edges in a graph
void Dijkstra(int Graph[n][n], int _n, int _s, int _d)
{
 
    int i, u, v, count;
    int dist[n];
    int Blackened[n] = { 0 };
    int pathlength[n] = { 0 };
    int parent[n];
 
    // The parent Of the source vertex is always equal to nill
    parent[_s] = NILL;
 
    // first, we initialize all distances to infinity.
    for (i = 0; i < n; i++)
        dist[i] = INFINITY;
 
    dist[_s] = 0;
    for (count = 0; count < n - 1; count++) {
        u = MinDistance(dist, Blackened);
 
        // if MinDistance() returns INFINITY, then the graph is not
        // connected and we have traversed all of the vertices in the
        // connected component of the source vertex, so it can reduce
        // the time complexity sometimes
        // In a directed graph, it means that the source vertex
        // is not a root
        if (u == INFINITY)
            break;
        else {
 
            // Mark the vertex as Blackened
            Blackened[u] = 1;
            for (v = 0; v < n; v++) {
                if (!Blackened[v] && Graph[u][v]
                    && dist[u] + Graph[u][v] < dist[v]) {
                    parent[v] = u;
                    pathlength[v] = pathlength[parent[v]] + 1;
                    dist[v] = dist[u] + Graph[u][v];
                }
                else if (!Blackened[v] && Graph[u][v]
                         && dist[u] + Graph[u][v] == dist[v]
                         && pathlength[u] + 1 < pathlength[v]) {
                    parent[v] = u;
                    pathlength[v] = pathlength[u] + 1;
                }
            }
        }
    }
 
    // Printing the path
    if (dist[_d] != INFINITY)
        PrintPath(parent, _d);
    else
        cout << "There is no path between vertex "
             << _s << "to vertex " << _d;
}
 
int MinDistance(int* dist, int* Blackened)
{
    int min = INFINITY, min_index, v;
    for (v = 0; v < n; v++)
        if (!Blackened[v] && dist[v] < min) {
            min = dist[v];
            min_index = v;
        }
    return min == INFINITY ? INFINITY : min_index;
}
 
// Function to print the path
void PrintPath(int* parent, int _d)
{
    if (parent[_d] == NILL) {
        cout << _d;
        return;
    }
    PrintPath(parent, parent[_d]);
    cout << "->" << _d;
}
 
// Driver code
int main()
{
    // INFINITY means that u and v are not neighbors.
    int Graph[n][n] = { { 0, 1, INFINITY, INFINITY, 10 },
                        { 1, 0, 4, INFINITY, INFINITY },
                        { INFINITY, 4, 0, 7, INFINITY },
                        { INFINITY, INFINITY, 7, 0, 2 },
                        { 10, INFINITY, INFINITY, 2, 0 } };
    Dijkstra(Graph, n, s, d);
    return 0;
}


Java
// Java program to find the shortest path
// with minimum edges in a graph
import java.io.*;
import java.util.*;
 
class GFG
{
 
    static int INFINITY = 9999, n = 5, s = 0, d = 3, NILL = -1;
 
    // Function to find the shortest path
    // with minimum edges in a graph
    static void Dijkstra(int[][] Graph, int _n, int _s, int _d)
    {
 
        int i, u, v, count;
        int[] dist = new int[n];
        int[] Blackened = new int[n];
        int[] pathlength = new int[n];
        int[] parent = new int[n];
 
        // The parent Of the source vertex is always equal to nill
        parent[_s] = NILL;
 
        // first, we initialize all distances to infinity.
        for (i = 0; i < n; i++)
            dist[i] = INFINITY;
 
        dist[_s] = 0;
        for (count = 0; count < n - 1; count++)
        {
            u = MinDistance(dist, Blackened);
 
            // if MinDistance() returns INFINITY, then the graph is not
            // connected and we have traversed all of the vertices in the
            // connected component of the source vertex, so it can reduce
            // the time complexity sometimes
            // In a directed graph, it means that the source vertex
            // is not a root
            if (u == INFINITY)
                break;
            else
            {
 
                // Mark the vertex as Blackened
                Blackened[u] = 1;
                for (v = 0; v < n; v++)
                {
                    if (Blackened[v] == 0 && Graph[u][v] != 0
                        && dist[u] + Graph[u][v] < dist[v])
                    {
                        parent[v] = u;
                        pathlength[v] = pathlength[parent[v]] + 1;
                        dist[v] = dist[u] + Graph[u][v];
                    }
                    else if (Blackened[v] == 0 && Graph[u][v] != 0
                            && dist[u] + Graph[u][v] == dist[v]
                            && pathlength[u] + 1 < pathlength[v])
                    {
                        parent[v] = u;
                        pathlength[v] = pathlength[u] + 1;
                    }
                }
            }
        }
 
        // Printing the path
        if (dist[_d] != INFINITY)
            PrintPath(parent, _d);
        else
            System.out.println("There is not path between vertex " +
                                _s + " to vertex " + _d);
    }
 
    static int MinDistance(int[] dist, int[] Blackened)
    {
        int min = INFINITY, min_index = -1, v;
        for (v = 0; v < n; v++)
            if (Blackened[v] == 0 && dist[v] < min)
            {
                min = dist[v];
                min_index = v;
            }
        return min == INFINITY ? INFINITY : min_index;
    }
 
    // Function to print the path
    static void PrintPath(int[] parent, int _d)
    {
        if (parent[_d] == NILL)
        {
            System.out.print(_d);
            return;
        }
        PrintPath(parent, parent[_d]);
        System.out.print("->" + _d);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // INFINITY means that u and v are not neighbors.
        int[][] Graph = { { 0, 1, INFINITY, INFINITY, 10 },
                        { 1, 0, 4, INFINITY, INFINITY },
                        { INFINITY, 4, 0, 7, INFINITY },
                        { INFINITY, INFINITY, 7, 0, 2 },
                        { 10, INFINITY, INFINITY, 2, 0 } };
        Dijkstra(Graph, n, s, d);
    }
}
 
// This code is contributed by
// sanjeev2552


Python
# Python program to find the shortest path
# with minimum edges in a graph
def Dijkstra(Graph, _s, _d):
    row = len(Graph)
    col = len(Graph[0])
    dist = [float("Inf")] * row
    Blackened =[0] * row
    pathlength =[0] * row
    parent = [-1] * row
    dist[_s]= 0
    for count in range(row-1):
        u = MinDistance(dist, Blackened)
 
        # if MinDistance() returns INFINITY, then the graph is not
        # connected and we have traversed all of the vertices in the
        # connected component of the source vertex, so it can reduce
        # the time complexity sometimes
        # In a directed graph, it means that the source vertex
        # is not a root
        if u == float("Inf"):
            break
        else:
 
            # Mark the vertex as Blackened
            Blackened[u]= 1
        for v in range(row):
            if Blackened[v]== 0 and Graph[u][v] and dist[u]+Graph[u][v]", _d,
def MinDistance(dist, Blackened):
    min = float("Inf")
    for v in range(len(dist)):
        if not Blackened[v] and dist[v]


输出:
0->4->3

时间复杂度: O(V^2),其中 V 是顶点数,E 是边数。
辅助空间: O(V + E)

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