📌  相关文章
📜  未加权图中的最短路径

📅  最后修改于: 2022-05-13 01:57:54.559000             🧑  作者: Mango

未加权图中的最短路径

给定一个未加权的图、一个源和一个目的地,我们需要以最优的方式在图中找到从源到目的地的最短路径。

未加权图

8个顶点的未加权图

Input: source vertex = 0 and destination vertex is = 7.
Output: Shortest path length is:2
        Path is::
        0 3 7

Input: source vertex is = 2 and destination vertex is = 6.
Output: Shortest path length is:5
        Path is::
        2 1 0 3 4 6

一种解决方案是使用 Bellman-Ford 在 O(VE) 时间内求解。如果没有负权重循环,那么我们可以使用 Dijkstra 算法在 O(E + VLogV) 时间内求解。
由于图没有加权,我们可以在 O(V + E) 时间内解决这个问题。这个想法是使用广度优先搜索的修改版本,其中我们在进行广度优先搜索时继续存储给定顶点的前驱。
我们首先初始化一个数组 dist[0, 1, ...., v-1] 使得 dist[i] 存储顶点 i 到源顶点和数组 pred[0, 1, ....., v-1] 的距离使得 pred[i] 表示从源开始的广度优先搜索中顶点 i 的直接前驱。
现在我们在 O(1) 时间内从数组 d 中获得从源到任何其他顶点的路径长度,并且为了打印从源到任何顶点的路径,我们可以使用数组 p,这将花费 O(V) 时间在最坏的情况下因为 V 是数组 P 的大小。所以算法的大部分时间都花在从给定的源中进行广度优先搜索,我们知道这需要 O(V+E) 时间。因此我们算法的时间复杂度是 O(V+E)。
以下面的未加权图为例:
以下是寻找最短路径的完整算法:

C++
// CPP code for printing shortest path between
// two vertices of unweighted graph
#include 
using namespace std;
 
// utility function to form edge between two vertices
// source and dest
void add_edge(vector adj[], int src, int dest)
{
    adj[src].push_back(dest);
    adj[dest].push_back(src);
}
 
// a modified version of BFS that stores predecessor
// of each vertex in array p
// and its distance from source in array d
bool BFS(vector adj[], int src, int dest, int v,
         int pred[], int dist[])
{
    // a queue to maintain queue of vertices whose
    // adjacency list is to be scanned as per normal
    // DFS algorithm
    list queue;
 
    // boolean array visited[] which stores the
    // information whether ith vertex is reached
    // at least once in the Breadth first search
    bool visited[v];
 
    // initially all vertices are unvisited
    // so v[i] for all i is false
    // and as no path is yet constructed
    // dist[i] for all i set to infinity
    for (int i = 0; i < v; i++) {
        visited[i] = false;
        dist[i] = INT_MAX;
        pred[i] = -1;
    }
 
    // now source is first to be visited and
    // distance from source to itself should be 0
    visited[src] = true;
    dist[src] = 0;
    queue.push_back(src);
 
    // standard BFS algorithm
    while (!queue.empty()) {
        int u = queue.front();
        queue.pop_front();
        for (int i = 0; i < adj[u].size(); i++) {
            if (visited[adj[u][i]] == false) {
                visited[adj[u][i]] = true;
                dist[adj[u][i]] = dist[u] + 1;
                pred[adj[u][i]] = u;
                queue.push_back(adj[u][i]);
 
                // We stop BFS when we find
                // destination.
                if (adj[u][i] == dest)
                    return true;
            }
        }
    }
 
    return false;
}
 
// utility function to print the shortest distance
// between source vertex and destination vertex
void printShortestDistance(vector adj[], int s,
                           int dest, int v)
{
    // predecessor[i] array stores predecessor of
    // i and distance array stores distance of i
    // from s
    int pred[v], dist[v];
 
    if (BFS(adj, s, dest, v, pred, dist) == false) {
        cout << "Given source and destination"
             << " are not connected";
        return;
    }
 
    // vector path stores the shortest path
    vector path;
    int crawl = dest;
    path.push_back(crawl);
    while (pred[crawl] != -1) {
        path.push_back(pred[crawl]);
        crawl = pred[crawl];
    }
 
    // distance from source is in distance array
    cout << "Shortest path length is : "
         << dist[dest];
 
    // printing path from source to destination
    cout << "\nPath is::\n";
    for (int i = path.size() - 1; i >= 0; i--)
        cout << path[i] << " ";
}
 
// Driver program to test above functions
int main()
{
    // no. of vertices
    int v = 8;
 
    // array of vectors is used to store the graph
    // in the form of an adjacency list
    vector adj[v];
 
    // Creating graph given in the above diagram.
    // add_edge function takes adjacency list, source
    // and destination vertex as argument and forms
    // an edge between them.
    add_edge(adj, 0, 1);
    add_edge(adj, 0, 3);
    add_edge(adj, 1, 2);
    add_edge(adj, 3, 4);
    add_edge(adj, 3, 7);
    add_edge(adj, 4, 5);
    add_edge(adj, 4, 6);
    add_edge(adj, 4, 7);
    add_edge(adj, 5, 6);
    add_edge(adj, 6, 7);
    int source = 0, dest = 7;
    printShortestDistance(adj, source, dest, v);
    return 0;
}


Java
// Java program to find shortest path in an undirected
// graph
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
 
public class pathUnweighted {
 
    // Driver Program
    public static void main(String args[])
    {
        // No of vertices
        int v = 8;
 
        // Adjacency list for storing which vertices are connected
        ArrayList> adj =
                            new ArrayList>(v);
        for (int i = 0; i < v; i++) {
            adj.add(new ArrayList());
        }
 
        // Creating graph given in the above diagram.
        // add_edge function takes adjacency list, source
        // and destination vertex as argument and forms
        // an edge between them.
        addEdge(adj, 0, 1);
        addEdge(adj, 0, 3);
        addEdge(adj, 1, 2);
        addEdge(adj, 3, 4);
        addEdge(adj, 3, 7);
        addEdge(adj, 4, 5);
        addEdge(adj, 4, 6);
        addEdge(adj, 4, 7);
        addEdge(adj, 5, 6);
        addEdge(adj, 6, 7);
        int source = 0, dest = 7;
        printShortestDistance(adj, source, dest, v);
    }
 
    // function to form edge between two vertices
    // source and dest
    private static void addEdge(ArrayList> adj, int i, int j)
    {
        adj.get(i).add(j);
        adj.get(j).add(i);
    }
 
    // function to print the shortest distance and path
    // between source vertex and destination vertex
    private static void printShortestDistance(
                     ArrayList> adj,
                             int s, int dest, int v)
    {
        // predecessor[i] array stores predecessor of
        // i and distance array stores distance of i
        // from s
        int pred[] = new int[v];
        int dist[] = new int[v];
 
        if (BFS(adj, s, dest, v, pred, dist) == false) {
            System.out.println("Given source and destination" +
                                         "are not connected");
            return;
        }
 
        // LinkedList to store path
        LinkedList path = new LinkedList();
        int crawl = dest;
        path.add(crawl);
        while (pred[crawl] != -1) {
            path.add(pred[crawl]);
            crawl = pred[crawl];
        }
 
        // Print distance
        System.out.println("Shortest path length is: " + dist[dest]);
 
        // Print path
        System.out.println("Path is ::");
        for (int i = path.size() - 1; i >= 0; i--) {
            System.out.print(path.get(i) + " ");
        }
    }
 
    // a modified version of BFS that stores predecessor
    // of each vertex in array pred
    // and its distance from source in array dist
    private static boolean BFS(ArrayList> adj, int src,
                                  int dest, int v, int pred[], int dist[])
    {
        // a queue to maintain queue of vertices whose
        // adjacency list is to be scanned as per normal
        // BFS algorithm using LinkedList of Integer type
        LinkedList queue = new LinkedList();
 
        // boolean array visited[] which stores the
        // information whether ith vertex is reached
        // at least once in the Breadth first search
        boolean visited[] = new boolean[v];
 
        // initially all vertices are unvisited
        // so v[i] for all i is false
        // and as no path is yet constructed
        // dist[i] for all i set to infinity
        for (int i = 0; i < v; i++) {
            visited[i] = false;
            dist[i] = Integer.MAX_VALUE;
            pred[i] = -1;
        }
 
        // now source is first to be visited and
        // distance from source to itself should be 0
        visited[src] = true;
        dist[src] = 0;
        queue.add(src);
 
        // bfs Algorithm
        while (!queue.isEmpty()) {
            int u = queue.remove();
            for (int i = 0; i < adj.get(u).size(); i++) {
                if (visited[adj.get(u).get(i)] == false) {
                    visited[adj.get(u).get(i)] = true;
                    dist[adj.get(u).get(i)] = dist[u] + 1;
                    pred[adj.get(u).get(i)] = u;
                    queue.add(adj.get(u).get(i));
 
                    // stopping condition (when we find
                    // our destination)
                    if (adj.get(u).get(i) == dest)
                        return true;
                }
            }
        }
        return false;
    }
}
// This code is contributed by Sahil Vaid


Python3
# Python3 code for printing shortest path between
# two vertices of unweighted graph
  
# utility function to form edge between two vertices
# source and dest
def add_edge(adj, src, dest):
 
    adj[src].append(dest);
    adj[dest].append(src);
  
# a modified version of BFS that stores predecessor
# of each vertex in array p
# and its distance from source in array d
def BFS(adj, src, dest, v, pred, dist):
 
    # a queue to maintain queue of vertices whose
    # adjacency list is to be scanned as per normal
    # DFS algorithm
    queue = []
  
    # boolean array visited[] which stores the
    # information whether ith vertex is reached
    # at least once in the Breadth first search
    visited = [False for i in range(v)];
  
    # initially all vertices are unvisited
    # so v[i] for all i is false
    # and as no path is yet constructed
    # dist[i] for all i set to infinity
    for i in range(v):
 
        dist[i] = 1000000
        pred[i] = -1;
     
    # now source is first to be visited and
    # distance from source to itself should be 0
    visited[src] = True;
    dist[src] = 0;
    queue.append(src);
  
    # standard BFS algorithm
    while (len(queue) != 0):
        u = queue[0];
        queue.pop(0);
        for i in range(len(adj[u])):
         
            if (visited[adj[u][i]] == False):
                visited[adj[u][i]] = True;
                dist[adj[u][i]] = dist[u] + 1;
                pred[adj[u][i]] = u;
                queue.append(adj[u][i]);
  
                # We stop BFS when we find
                # destination.
                if (adj[u][i] == dest):
                    return True;
  
    return False;
  
# utility function to print the shortest distance
# between source vertex and destination vertex
def printShortestDistance(adj, s, dest, v):
     
    # predecessor[i] array stores predecessor of
    # i and distance array stores distance of i
    # from s
    pred=[0 for i in range(v)]
    dist=[0 for i in range(v)];
  
    if (BFS(adj, s, dest, v, pred, dist) == False):
        print("Given source and destination are not connected")
  
    # vector path stores the shortest path
    path = []
    crawl = dest;
    crawl = dest;
    path.append(crawl);
     
    while (pred[crawl] != -1):
        path.append(pred[crawl]);
        crawl = pred[crawl];
     
  
    # distance from source is in distance array
    print("Shortest path length is : " + str(dist[dest]), end = '')
  
    # printing path from source to destination
    print("\nPath is : : ")
     
    for i in range(len(path)-1, -1, -1):
        print(path[i], end=' ')
         
# Driver program to test above functions
if __name__=='__main__':
     
    # no. of vertices
    v = 8;
  
    # array of vectors is used to store the graph
    # in the form of an adjacency list
    adj = [[] for i in range(v)];
  
    # Creating graph given in the above diagram.
    # add_edge function takes adjacency list, source
    # and destination vertex as argument and forms
    # an edge between them.
    add_edge(adj, 0, 1);
    add_edge(adj, 0, 3);
    add_edge(adj, 1, 2);
    add_edge(adj, 3, 4);
    add_edge(adj, 3, 7);
    add_edge(adj, 4, 5);
    add_edge(adj, 4, 6);
    add_edge(adj, 4, 7);
    add_edge(adj, 5, 6);
    add_edge(adj, 6, 7);
    source = 0
    dest = 7;
    printShortestDistance(adj, source, dest, v);
 
    # This code is contributed by rutvik_56


C#
// C# program to find shortest
// path in an undirected graph
using System;
using System.Collections.Generic;
class pathUnweighted{
 
// Driver code
public static void Main(String []args)
{
  // No of vertices
  int v = 8;
 
  // Adjacency list for storing
  // which vertices are connected
  List> adj =
            new List>(v);
   
  for (int i = 0; i < v; i++)
  {
    adj.Add(new List());
  }
 
  // Creating graph given in the
  // above diagram. add_edge
  // function takes adjacency list,
  // source and destination vertex
  // as argument and forms an edge
  // between them.
  addEdge(adj, 0, 1);
  addEdge(adj, 0, 3);
  addEdge(adj, 1, 2);
  addEdge(adj, 3, 4);
  addEdge(adj, 3, 7);
  addEdge(adj, 4, 5);
  addEdge(adj, 4, 6);
  addEdge(adj, 4, 7);
  addEdge(adj, 5, 6);
  addEdge(adj, 6, 7);
  int source = 0, dest = 7;
  printShortestDistance(adj, source,
                        dest, v);
}
 
// function to form edge between
// two vertices source and dest
private static void addEdge(List> adj,
                            int i, int j)
{
  adj[i].Add(j);
  adj[j].Add(i);
}
 
// function to print the shortest
// distance and path between source
// vertex and destination vertex
private static void printShortestDistance(List> adj,
                                          int s, int dest, int v)
{
  // predecessor[i] array stores
  // predecessor of i and distance
  // array stores distance of i
  // from s
  int []pred = new int[v];
  int []dist = new int[v];
 
  if (BFS(adj, s, dest,
          v, pred, dist) == false)
  {
    Console.WriteLine("Given source and destination" +
                      "are not connected");
    return;
  }
 
  // List to store path
  List path = new List();
  int crawl = dest;
  path.Add(crawl);
   
  while (pred[crawl] != -1)
  {
    path.Add(pred[crawl]);
    crawl = pred[crawl];
  }
 
  // Print distance
  Console.WriteLine("Shortest path length is: " +
                     dist[dest]);
 
  // Print path
  Console.WriteLine("Path is ::");
   
  for (int i = path.Count - 1;
           i >= 0; i--)
  {
    Console.Write(path[i] + " ");
  }
}
 
// a modified version of BFS that
// stores predecessor of each vertex
// in array pred and its distance
// from source in array dist
private static bool BFS(List> adj,
                        int src, int dest,
                        int v, int []pred,
                        int []dist)
{
  // a queue to maintain queue of
  // vertices whose adjacency list
  // is to be scanned as per normal
  // BFS algorithm using List of int type
  List queue = new List();
 
  // bool array visited[] which
  // stores the information whether
  // ith vertex is reached at least
  // once in the Breadth first search
  bool []visited = new bool[v];
 
  // initially all vertices are
  // unvisited so v[i] for all i
  // is false and as no path is
  // yet constructed dist[i] for
  // all i set to infinity
  for (int i = 0; i < v; i++)
  {
    visited[i] = false;
    dist[i] = int.MaxValue;
    pred[i] = -1;
  }
 
  // now source is first to be
  // visited and distance from
  // source to itself should be 0
  visited[src] = true;
  dist[src] = 0;
  queue.Add(src);
 
  // bfs Algorithm
  while (queue.Count != 0)
  {
    int u = queue[0];
    queue.RemoveAt(0);
     
    for (int i = 0;
             i < adj[u].Count; i++)
    {
      if (visited[adj[u][i]] == false)
      {
        visited[adj[u][i]] = true;
        dist[adj[u][i]] = dist[u] + 1;
        pred[adj[u][i]] = u;
        queue.Add(adj[u][i]);
 
        // stopping condition (when we
        // find our destination)
        if (adj[u][i] == dest)
          return true;
      }
    }
  }
  return false;
}
}
 
// This code is contributed by Rajput-Ji


输出:
Shortest path length is : 2
Path is::
0 3 7

时间复杂度:O(V + E)
辅助空间:O(V)