📌  相关文章
📜  在有向图和加权图中具有恰好为k个边的最短路径

📅  最后修改于: 2021-04-27 22:38:21             🧑  作者: Mango

给定其中有向和两个顶点’u’和’v’,找到从’u’到’v’的最短路径,路径上恰好有k条边。

该图以邻接矩阵表示形式给出,其中graph [i] [j]的值指示从顶点i到顶点j的边的权重,值INF(infinite)指示从i到j的边。

例如,考虑下图。令源’u’为顶点0,目标’v’为3,k为2。有两个长度为2的游程,游程分别为{0,2,3}和{0,1,3}。两者中最短的是{0,2,3},路径权重是3 + 6 = 9。

图1

这个想法是使用上一篇文章中讨论的方法浏览从u到v长度为k的所有路径,并返回最短路径的权重。一个简单的解决方案是从u开始,转到所有相邻的顶点,然后对k为k-1,源为相邻顶点,目标为v的相邻顶点递归。以下是此简单解决方案的C++和Java实现。

C++
// C++ program to find shortest path with exactly k edges
#include 
using namespace std;
  
// Define number of vertices in the graph and inifinite value
#define V 4
#define INF INT_MAX
  
// A naive recursive function to count walks from u to v with k edges
int shortestPath(int graph[][V], int u, int v, int k)
{
   // Base cases
   if (k == 0 && u == v)             return 0;
   if (k == 1 && graph[u][v] != INF) return graph[u][v];
   if (k <= 0)                       return INF;
  
   // Initialize result
   int res = INF;
  
   // Go to all adjacents of u and recur
   for (int i = 0; i < V; i++)
   {
       if (graph[u][i] != INF && u != i && v != i)
       {
           int rec_res = shortestPath(graph, i, v, k-1);
           if (rec_res != INF)
              res = min(res, graph[u][i] + rec_res);
       }
   }
   return res;
}
  
// driver program to test above function
int main()
{
    /* Let us create the graph shown in above diagram*/
     int graph[V][V] = { {0, 10, 3, 2},
                        {INF, 0, INF, 7},
                        {INF, INF, 0, 6},
                        {INF, INF, INF, 0}
                      };
    int u = 0, v = 3, k = 2;
    cout << "Weight of the shortest path is " <<
          shortestPath(graph, u, v, k);
    return 0;
}


Java
// Dynamic Programming based Java program to find shortest path
// with exactly k edges
import java.util.*;
import java.lang.*;
import java.io.*;
  
class ShortestPath
{
    // Define number of vertices in the graph and inifinite value
    static final int V = 4;
    static final int INF = Integer.MAX_VALUE;
  
    // A naive recursive function to count walks from u to v
    // with k edges
    int shortestPath(int graph[][], int u, int v, int k)
    {
        // Base cases
        if (k == 0 && u == v)             return 0;
        if (k == 1 && graph[u][v] != INF) return graph[u][v];
        if (k <= 0)                       return INF;
  
        // Initialize result
        int res = INF;
  
        // Go to all adjacents of u and recur
        for (int i = 0; i < V; i++)
        {
            if (graph[u][i] != INF && u != i && v != i)
            {
                int rec_res = shortestPath(graph, i, v, k-1);
                if (rec_res != INF)
                    res = Math.min(res, graph[u][i] + rec_res);
            }
        }
        return res;
    }
  
    public static void main (String[] args)
    {
        /* Let us create the graph shown in above diagram*/
        int graph[][] = new int[][]{ {0, 10, 3, 2},
                                     {INF, 0, INF, 7},
                                     {INF, INF, 0, 6},
                                     {INF, INF, INF, 0}
                                   };
        ShortestPath t = new ShortestPath();
        int u = 0, v = 3, k = 2;
        System.out.println("Weight of the shortest path is "+
                           t.shortestPath(graph, u, v, k));
    }
}


Python3
# Python3 program to find shortest path 
# with exactly k edges 
  
# Define number of vertices in the graph
# and inifinite value 
  
# A naive recursive function to count
# walks from u to v with k edges 
def shortestPath(graph, u, v, k):
    V = 4
    INF = 999999999999
      
    # Base cases 
    if k == 0 and u == v:
        return 0
    if k == 1 and graph[u][v] != INF:
        return graph[u][v] 
    if k <= 0:
        return INF 
  
# Initialize result 
    res = INF 
  
# Go to all adjacents of u and recur
    for i in range(V):
        if graph[u][i] != INF and u != i and v != i:
            rec_res = shortestPath(graph, i, v, k - 1) 
            if rec_res != INF:
                res = min(res, graph[u][i] + rec_res)
    return res
  
# Driver Code
if __name__ == '__main__':
    INF = 999999999999
      
    # Let us create the graph shown
    # in above diagram
    graph = [[0, 10, 3, 2],
             [INF, 0, INF, 7],
             [INF, INF, 0, 6],
             [INF, INF, INF, 0]]
    u = 0
    v = 3
    k = 2
    print("Weight of the shortest path is",
              shortestPath(graph, u, v, k))
  
# This code is contributed by PranchalK


C#
// Dynamic Programming based C# program to 
// find shortest pathwith exactly k edges
using System;
  
class GFG
{
      
// Define number of vertices in the 
// graph and inifinite value
const int V = 4;
const int INF = Int32.MaxValue;
  
// A naive recursive function to count 
// walks from u to v with k edges
int shortestPath(int[,] graph, int u, 
                 int v, int k)
{
    // Base cases
    if (k == 0 && u == v)         return 0;
    if (k == 1 && graph[u, v] != INF) return graph[u, v];
    if (k <= 0)                 return INF;
  
    // Initialize result
    int res = INF;
  
    // Go to all adjacents of u and recur
    for (int i = 0; i < V; i++)
    {
        if (graph[u, i] != INF && u != i && v != i)
        {
            int rec_res = shortestPath(graph, i, v, k - 1);
            if (rec_res != INF)
                res = Math.Min(res, graph[u, i] + rec_res);
        }
    }
    return res;
}
  
// Driver Code
public static void Main ()
{
    /* Let us create the graph 
       shown in above diagram*/
    int[,] graph = new int[,]{{0, 10, 3, 2},
                              {INF, 0, INF, 7},
                              {INF, INF, 0, 6},
                              {INF, INF, INF, 0}};
    GFG t = new GFG();
    int u = 0, v = 3, k = 2;
    Console.WriteLine("Weight of the shortest path is "+
                      t.shortestPath(graph, u, v, k));
}
}
  
// This code is contributed by Akanksha Rai


C++
// Dynamic Programming based C++ program to find shortest path with
// exactly k edges
#include 
#include 
using namespace std;
  
// Define number of vertices in the graph and inifinite value
#define V 4
#define INF INT_MAX
  
// A Dynamic programming based function to find the shortest path from
// u to v with exactly k edges.
int shortestPath(int graph[][V], int u, int v, int k)
{
    // Table to be filled up using DP. The value sp[i][j][e] will store
    // weight of the shortest path from i to j with exactly k edges
    int sp[V][V][k+1];
  
    // Loop for number of edges from 0 to k
    for (int e = 0; e <= k; e++)
    {
        for (int i = 0; i < V; i++)  // for source
        {
            for (int j = 0; j < V; j++) // for destination
            {
                // initialize value
                sp[i][j][e] = INF;
  
                // from base cases
                if (e == 0 && i == j)
                    sp[i][j][e] = 0;
                if (e == 1 && graph[i][j] != INF)
                    sp[i][j][e] = graph[i][j];
  
                //go to adjacent only when number of edges is more than 1
                if (e > 1)
                {
                    for (int a = 0; a < V; a++)
                    {
                        // There should be an edge from i to a and a 
                        // should not be same as either i or j
                        if (graph[i][a] != INF && i != a &&
                            j!= a && sp[a][j][e-1] != INF)
                          sp[i][j][e] = min(sp[i][j][e], graph[i][a] +
                                                       sp[a][j][e-1]);
                    }
                }
           }
        }
    }
    return sp[u][v][k];
}
  
// driver program to test above function
int main()
{
    /* Let us create the graph shown in above diagram*/
     int graph[V][V] = { {0, 10, 3, 2},
                        {INF, 0, INF, 7},
                        {INF, INF, 0, 6},
                        {INF, INF, INF, 0}
                      };
    int u = 0, v = 3, k = 2;
    cout << shortestPath(graph, u, v, k);
    return 0;
}


Java
// Dynamic Programming based Java program to find shortest path with
// exactly k edges
import java.util.*;
import java.lang.*;
import java.io.*;
  
class ShortestPath
{
    // Define number of vertices in the graph and inifinite value
    static final int V = 4;
    static final int INF = Integer.MAX_VALUE;
  
    // A Dynamic programming based function to find the shortest path
    // from u to v with exactly k edges.
    int shortestPath(int graph[][], int u, int v, int k)
    {
        // Table to be filled up using DP. The value sp[i][j][e] will
        // store weight of the shortest path from i to j with exactly
        // k edges
        int sp[][][] = new int[V][V][k+1];
  
        // Loop for number of edges from 0 to k
        for (int e = 0; e <= k; e++)
        {
            for (int i = 0; i < V; i++)  // for source
            {
                for (int j = 0; j < V; j++) // for destination
                {
                    // initialize value
                    sp[i][j][e] = INF;
  
                    // from base cases
                    if (e == 0 && i == j)
                        sp[i][j][e] = 0;
                    if (e == 1 && graph[i][j] != INF)
                        sp[i][j][e] = graph[i][j];
  
                    // go to adjacent only when number of edges is
                    // more than 1
                    if (e > 1)
                    {
                        for (int a = 0; a < V; a++)
                        {
                            // There should be an edge from i to a and
                            // a should not be same as either i or j
                            if (graph[i][a] != INF && i != a &&
                                    j!= a && sp[a][j][e-1] != INF)
                                sp[i][j][e] = Math.min(sp[i][j][e],
                                          graph[i][a] + sp[a][j][e-1]);
                        }
                    }
                }
            }
        }
        return sp[u][v][k];
    }
  
    public static void main (String[] args)
    {
        /* Let us create the graph shown in above diagram*/
        int graph[][] = new int[][]{ {0, 10, 3, 2},
                                     {INF, 0, INF, 7},
                                     {INF, INF, 0, 6},
                                     {INF, INF, INF, 0}
                                   };
        ShortestPath t = new ShortestPath();
        int u = 0, v = 3, k = 2;
        System.out.println("Weight of the shortest path is "+
                           t.shortestPath(graph, u, v, k));
    }
}
//This code is contributed by Aakash Hasija


Python3
# Dynamic Programming based Python3 
# program to find shortest path with
  
# A Dynamic programming based function 
# to find the shortest path from u to v 
# with exactly k edges. 
def shortestPath(graph, u, v, k):
    global V, INF
      
    # Table to be filled up using DP. The 
    # value sp[i][j][e] will store weight 
    # of the shortest path from i to j 
    # with exactly k edges 
    sp = [[None] * V for i in range(V)]
    for i in range(V):
        for j in range(V):
            sp[i][j] = [None] * (k + 1)
  
    # Loop for number of edges from 0 to k
    for e in range(k + 1):
        for i in range(V): # for source 
            for j in range(V): # for destination
              
                # initialize value 
                sp[i][j][e] = INF
  
                # from base cases 
                if (e == 0 and i == j): 
                    sp[i][j][e] = 0
                if (e == 1 and graph[i][j] != INF):
                    sp[i][j][e] = graph[i][j] 
  
                # go to adjacent only when number
                # of edges is more than 1 
                if (e > 1):
                    for a in range(V):
                          
                        # There should be an edge from
                        # i to a and a should not be
                        # same as either i or j 
                        if (graph[i][a] != INF and i != a and 
                             j!= a and sp[a][j][e - 1] != INF): 
                            sp[i][j][e] = min(sp[i][j][e], graph[i][a] + 
                                              sp[a][j][e - 1])
                          
    return sp[u][v][k]
  
# Driver Code
  
# Define number of vertices in
# the graph and inifinite value 
V = 4
INF = 999999999999
  
# Let us create the graph shown
# in above diagram
graph = [[0, 10, 3, 2], 
         [INF, 0, INF, 7], 
         [INF, INF, 0, 6], 
         [INF, INF, INF, 0]]
u = 0
v = 3
k = 2
print("Weight of the shortest path is",
          shortestPath(graph, u, v, k))
  
# This code is contributed by PranchalK


C#
// Dynamic Programming based C# program to find 
// shortest path with exactly k edges 
using System;
  
class GFG 
{ 
      
// Define number of vertices in the graph
// and inifinite value 
static readonly int V = 4; 
static readonly int INF = int.MaxValue; 
  
// A Dynamic programming based function to 
// find the shortest path from u to v
// with exactly k edges. 
int shortestPath(int [,]graph, int u, int v, int k) 
{ 
    // Table to be filled up using DP. The value 
    // sp[i][j][e] will store weight of the shortest 
    // path from i to j with exactly k edges 
    int [,,]sp = new int[V, V, k + 1]; 
  
    // Loop for number of edges from 0 to k 
    for (int e = 0; e <= k; e++) 
    { 
        for (int i = 0; i < V; i++) // for source 
        { 
            for (int j = 0; j < V; j++) // for destination 
            { 
                // initialize value 
                sp[i, j, e] = INF; 
  
                // from base cases 
                if (e == 0 && i == j) 
                    sp[i, j, e] = 0; 
                if (e == 1 && graph[i, j] != INF) 
                    sp[i, j, e] = graph[i, j]; 
  
                // go to adjacent only when number of 
                // edges is more than 1 
                if (e > 1) 
                { 
                    for (int a = 0; a < V; a++) 
                    { 
                        // There should be an edge from i to a and 
                        // a should not be same as either i or j 
                        if (graph[i, a] != INF && i != a && 
                                j!= a && sp[a, j, e - 1] != INF) 
                            sp[i, j, e] = Math.Min(sp[i, j, e], 
                                          graph[i, a] + sp[a, j, e - 1]); 
                    } 
                } 
            } 
        } 
    } 
    return sp[u, v, k]; 
} 
  
// Driver Code
public static void Main(String[] args) 
{ 
    /* Let us create the graph shown in above diagram*/
    int [,]graph = new int[,]{ {0, 10, 3, 2}, 
                               {INF, 0, INF, 7}, 
                               {INF, INF, 0, 6}, 
                               {INF, INF, INF, 0} }; 
    GFG t = new GFG(); 
    int u = 0, v = 3, k = 2; 
    Console.WriteLine("Weight of the shortest path is "+ 
                        t.shortestPath(graph, u, v, k)); 
} 
} 
  
// This code is contributed by 29AjayKumar


输出:

Weight of the shortest path is 9

上述函数的最坏情况下的时间复杂度是O(V k ),其中V是给定图中顶点的数量。我们可以通过绘制递归树来简单地分析时间复杂度。最坏的情况发生在完整的图形上。在最坏的情况下,递归树的每个内部节点都将恰好有V个子节点。
我们可以使用Dynamic Programming优化上述解决方案。这个想法是建立一个3D表,其中第一维是源,第二维是目标,第三维是从源到目标的边数,其值是走数。像其他动态编程问题一样,我们以自下而上的方式填充3D表。

C++

// Dynamic Programming based C++ program to find shortest path with
// exactly k edges
#include 
#include 
using namespace std;
  
// Define number of vertices in the graph and inifinite value
#define V 4
#define INF INT_MAX
  
// A Dynamic programming based function to find the shortest path from
// u to v with exactly k edges.
int shortestPath(int graph[][V], int u, int v, int k)
{
    // Table to be filled up using DP. The value sp[i][j][e] will store
    // weight of the shortest path from i to j with exactly k edges
    int sp[V][V][k+1];
  
    // Loop for number of edges from 0 to k
    for (int e = 0; e <= k; e++)
    {
        for (int i = 0; i < V; i++)  // for source
        {
            for (int j = 0; j < V; j++) // for destination
            {
                // initialize value
                sp[i][j][e] = INF;
  
                // from base cases
                if (e == 0 && i == j)
                    sp[i][j][e] = 0;
                if (e == 1 && graph[i][j] != INF)
                    sp[i][j][e] = graph[i][j];
  
                //go to adjacent only when number of edges is more than 1
                if (e > 1)
                {
                    for (int a = 0; a < V; a++)
                    {
                        // There should be an edge from i to a and a 
                        // should not be same as either i or j
                        if (graph[i][a] != INF && i != a &&
                            j!= a && sp[a][j][e-1] != INF)
                          sp[i][j][e] = min(sp[i][j][e], graph[i][a] +
                                                       sp[a][j][e-1]);
                    }
                }
           }
        }
    }
    return sp[u][v][k];
}
  
// driver program to test above function
int main()
{
    /* Let us create the graph shown in above diagram*/
     int graph[V][V] = { {0, 10, 3, 2},
                        {INF, 0, INF, 7},
                        {INF, INF, 0, 6},
                        {INF, INF, INF, 0}
                      };
    int u = 0, v = 3, k = 2;
    cout << shortestPath(graph, u, v, k);
    return 0;
}

Java

// Dynamic Programming based Java program to find shortest path with
// exactly k edges
import java.util.*;
import java.lang.*;
import java.io.*;
  
class ShortestPath
{
    // Define number of vertices in the graph and inifinite value
    static final int V = 4;
    static final int INF = Integer.MAX_VALUE;
  
    // A Dynamic programming based function to find the shortest path
    // from u to v with exactly k edges.
    int shortestPath(int graph[][], int u, int v, int k)
    {
        // Table to be filled up using DP. The value sp[i][j][e] will
        // store weight of the shortest path from i to j with exactly
        // k edges
        int sp[][][] = new int[V][V][k+1];
  
        // Loop for number of edges from 0 to k
        for (int e = 0; e <= k; e++)
        {
            for (int i = 0; i < V; i++)  // for source
            {
                for (int j = 0; j < V; j++) // for destination
                {
                    // initialize value
                    sp[i][j][e] = INF;
  
                    // from base cases
                    if (e == 0 && i == j)
                        sp[i][j][e] = 0;
                    if (e == 1 && graph[i][j] != INF)
                        sp[i][j][e] = graph[i][j];
  
                    // go to adjacent only when number of edges is
                    // more than 1
                    if (e > 1)
                    {
                        for (int a = 0; a < V; a++)
                        {
                            // There should be an edge from i to a and
                            // a should not be same as either i or j
                            if (graph[i][a] != INF && i != a &&
                                    j!= a && sp[a][j][e-1] != INF)
                                sp[i][j][e] = Math.min(sp[i][j][e],
                                          graph[i][a] + sp[a][j][e-1]);
                        }
                    }
                }
            }
        }
        return sp[u][v][k];
    }
  
    public static void main (String[] args)
    {
        /* Let us create the graph shown in above diagram*/
        int graph[][] = new int[][]{ {0, 10, 3, 2},
                                     {INF, 0, INF, 7},
                                     {INF, INF, 0, 6},
                                     {INF, INF, INF, 0}
                                   };
        ShortestPath t = new ShortestPath();
        int u = 0, v = 3, k = 2;
        System.out.println("Weight of the shortest path is "+
                           t.shortestPath(graph, u, v, k));
    }
}
//This code is contributed by Aakash Hasija

Python3

# Dynamic Programming based Python3 
# program to find shortest path with
  
# A Dynamic programming based function 
# to find the shortest path from u to v 
# with exactly k edges. 
def shortestPath(graph, u, v, k):
    global V, INF
      
    # Table to be filled up using DP. The 
    # value sp[i][j][e] will store weight 
    # of the shortest path from i to j 
    # with exactly k edges 
    sp = [[None] * V for i in range(V)]
    for i in range(V):
        for j in range(V):
            sp[i][j] = [None] * (k + 1)
  
    # Loop for number of edges from 0 to k
    for e in range(k + 1):
        for i in range(V): # for source 
            for j in range(V): # for destination
              
                # initialize value 
                sp[i][j][e] = INF
  
                # from base cases 
                if (e == 0 and i == j): 
                    sp[i][j][e] = 0
                if (e == 1 and graph[i][j] != INF):
                    sp[i][j][e] = graph[i][j] 
  
                # go to adjacent only when number
                # of edges is more than 1 
                if (e > 1):
                    for a in range(V):
                          
                        # There should be an edge from
                        # i to a and a should not be
                        # same as either i or j 
                        if (graph[i][a] != INF and i != a and 
                             j!= a and sp[a][j][e - 1] != INF): 
                            sp[i][j][e] = min(sp[i][j][e], graph[i][a] + 
                                              sp[a][j][e - 1])
                          
    return sp[u][v][k]
  
# Driver Code
  
# Define number of vertices in
# the graph and inifinite value 
V = 4
INF = 999999999999
  
# Let us create the graph shown
# in above diagram
graph = [[0, 10, 3, 2], 
         [INF, 0, INF, 7], 
         [INF, INF, 0, 6], 
         [INF, INF, INF, 0]]
u = 0
v = 3
k = 2
print("Weight of the shortest path is",
          shortestPath(graph, u, v, k))
  
# This code is contributed by PranchalK

C#

// Dynamic Programming based C# program to find 
// shortest path with exactly k edges 
using System;
  
class GFG 
{ 
      
// Define number of vertices in the graph
// and inifinite value 
static readonly int V = 4; 
static readonly int INF = int.MaxValue; 
  
// A Dynamic programming based function to 
// find the shortest path from u to v
// with exactly k edges. 
int shortestPath(int [,]graph, int u, int v, int k) 
{ 
    // Table to be filled up using DP. The value 
    // sp[i][j][e] will store weight of the shortest 
    // path from i to j with exactly k edges 
    int [,,]sp = new int[V, V, k + 1]; 
  
    // Loop for number of edges from 0 to k 
    for (int e = 0; e <= k; e++) 
    { 
        for (int i = 0; i < V; i++) // for source 
        { 
            for (int j = 0; j < V; j++) // for destination 
            { 
                // initialize value 
                sp[i, j, e] = INF; 
  
                // from base cases 
                if (e == 0 && i == j) 
                    sp[i, j, e] = 0; 
                if (e == 1 && graph[i, j] != INF) 
                    sp[i, j, e] = graph[i, j]; 
  
                // go to adjacent only when number of 
                // edges is more than 1 
                if (e > 1) 
                { 
                    for (int a = 0; a < V; a++) 
                    { 
                        // There should be an edge from i to a and 
                        // a should not be same as either i or j 
                        if (graph[i, a] != INF && i != a && 
                                j!= a && sp[a, j, e - 1] != INF) 
                            sp[i, j, e] = Math.Min(sp[i, j, e], 
                                          graph[i, a] + sp[a, j, e - 1]); 
                    } 
                } 
            } 
        } 
    } 
    return sp[u, v, k]; 
} 
  
// Driver Code
public static void Main(String[] args) 
{ 
    /* Let us create the graph shown in above diagram*/
    int [,]graph = new int[,]{ {0, 10, 3, 2}, 
                               {INF, 0, INF, 7}, 
                               {INF, INF, 0, 6}, 
                               {INF, INF, INF, 0} }; 
    GFG t = new GFG(); 
    int u = 0, v = 3, k = 2; 
    Console.WriteLine("Weight of the shortest path is "+ 
                        t.shortestPath(graph, u, v, k)); 
} 
} 
  
// This code is contributed by 29AjayKumar

输出:

Weight of the shortest path is 9

上述基于DP的解决方案的时间复杂度为O(V 3 K),这比朴素的解决方案要好得多。