📜  Dijkstra的最短路径和最少的边缘

📅  最后修改于: 2021-05-07 08:12:04             🧑  作者: 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 。因此,我们将其权重从无穷大更新为5 + 7 = 12,然后将其父级设置为2 ,并将其pathlength []设置为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