📌  相关文章
📜  查找两个顶点之间的最大边不相交路径数

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

查找两个顶点之间的最大边不相交路径数

给定一个有向图和其中的两个顶点,源“s”和目标“t”,找出从 s 到 t 的边不相交路径的最大数量。如果两条路径不共享任何边,则称它们为边不相交。

边缘不相交1

在上图中,从源 0 到目标 7 最多可以有两条边不相交的路径。下面以红色和蓝色突出显示的两条边缘不相交路径是 0-2-6-7 和 0-3-6-5-7。

边缘不相交2

请注意,路径可能不同,但最大数量相同。例如,在上图中,另一组可能的路径分别是 0-1-2-6-7 和 0-3-6-5-7。

这个问题可以通过减少到最大流量问题来解决。以下是步骤。
1)将给定的源和目的地视为流网络中的源和汇。为每条边分配单位容量。
2)运行 Ford-Fulkerson 算法以找到从源到汇的最大流量。
3)最大流量等于边不相交路径的最大数量。

当我们运行 Ford-Fulkerson 时,我们将容量减少了一个单位。因此,边缘不能再次使用。所以最大流量等于边不相交路径的最大数量。

以下是上述算法的实现。大部分代码都取自这里。

C++
// C++ program to find maximum number of edge disjoint paths
#include 
#include 
#include 
#include 
using namespace std;
 
// Number of vertices in given graph
#define V 8
 
/* Returns true if there is a path from source 's' to sink 't' in
residual graph. Also fills parent[] to store the path */
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
    // Create a visited array and mark all vertices as not visited
    bool visited[V];
    memset(visited, 0, sizeof(visited));
 
    // Create a queue, enqueue source vertex and mark source vertex
    // as visited
    queue  q;
    q.push(s);
    visited[s] = true;
    parent[s] = -1;
 
    // Standard BFS Loop
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
 
        for (int v=0; v 0)
            {
                q.push(v);
                parent[v] = u;
                visited[v] = true;
            }
        }
    }
 
    // If we reached sink in BFS starting from source, then return
    // true, else false
    return (visited[t] == true);
}
 
// Returns the maximum number of edge-disjoint paths from s to t.
// This function is copy of forFulkerson() discussed at http://goo.gl/wtQ4Ks
int findDisjointPaths(int graph[V][V], int s, int t)
{
    int u, v;
 
    // Create a residual graph and fill the residual graph with
    // given capacities in the original graph as residual capacities
    // in residual graph
    int rGraph[V][V]; // Residual graph where rGraph[i][j] indicates
                    // residual capacity of edge from i to j (if there
                    // is an edge. If rGraph[i][j] is 0, then there is not)
    for (u = 0; u < V; u++)
        for (v = 0; v < V; v++)
            rGraph[u][v] = graph[u][v];
 
    int parent[V]; // This array is filled by BFS and to store path
 
    int max_flow = 0; // There is no flow initially
 
    // Augment the flow while there is path from source to sink
    while (bfs(rGraph, s, t, parent))
    {
        // Find minimum residual capacity of the edges along the
        // path filled by BFS. Or we can say find the maximum flow
        // through the path found.
        int path_flow = INT_MAX;
 
        for (v=t; v!=s; v=parent[v])
        {
            u = parent[v];
            path_flow = min(path_flow, rGraph[u][v]);
        }
 
        // update residual capacities of the edges and reverse edges
        // along the path
        for (v=t; v != s; v=parent[v])
        {
            u = parent[v];
            rGraph[u][v] -= path_flow;
            rGraph[v][u] += path_flow;
        }
 
        // Add path flow to overall flow
        max_flow += path_flow;
    }
 
    // Return the overall flow (max_flow is equal to maximum
    // number of edge-disjoint paths)
    return max_flow;
}
 
// Driver program to test above functions
int main()
{
    // Let us create a graph shown in the above example
    int graph[V][V] = { {0, 1, 1, 1, 0, 0, 0, 0},
                        {0, 0, 1, 0, 0, 0, 0, 0},
                        {0, 0, 0, 1, 0, 0, 1, 0},
                        {0, 0, 0, 0, 0, 0, 1, 0},
                        {0, 0, 1, 0, 0, 0, 0, 1},
                        {0, 1, 0, 0, 0, 0, 0, 1},
                        {0, 0, 0, 0, 0, 1, 0, 1},
                        {0, 0, 0, 0, 0, 0, 0, 0}
                    };
 
    int s = 0;
    int t = 7;
    cout << "There can be maximum " << findDisjointPaths(graph, s, t)
        << " edge-disjoint paths from " << s <<" to "<< t ;
 
    return 0;
}


Java
// Java program to find maximum number
// of edge disjoint paths
import java.util.*;
 
class GFG
{
 
// Number of vertices in given graph
static int V = 8;
 
/* Returns true if there is a path from
source 's' to sink 't' in residual graph.
Also fills parent[] to store the path */
static boolean bfs(int rGraph[][], int s,
                   int t, int parent[])
{
    // Create a visited array and
    // mark all vertices as not visited
    boolean []visited = new boolean[V];
 
 
    // Create a queue, enqueue source vertex and
    // mark source vertex as visited
    Queue  q = new LinkedList<>();
    q.add(s);
    visited[s] = true;
    parent[s] = -1;
 
    // Standard BFS Loop
    while (!q.isEmpty())
    {
        int u = q.peek();
        q.remove();
 
        for (int v = 0; v < V; v++)
        {
            if (visited[v] == false &&
                rGraph[u][v] > 0)
            {
                q.add(v);
                parent[v] = u;
                visited[v] = true;
            }
        }
    }
 
    // If we reached sink in BFS
    // starting from source, then
    // return true, else false
    return (visited[t] == true);
}
 
// Returns the maximum number of edge-disjoint
// paths from s to t. This function is copy of
// forFulkerson() discussed at http://goo.gl/wtQ4Ks
static int findDisjointPaths(int graph[][], int s, int t)
{
    int u, v;
 
    // Create a residual graph and fill the
    // residual graph with given capacities
    // in the original graph as residual capacities
    // in residual graph
     
    // Residual graph where rGraph[i][j] indicates
    // residual capacity of edge from i to j (if there
    // is an edge. If rGraph[i][j] is 0, then there is not)
    int [][]rGraph = new int[V][V];
    for (u = 0; u < V; u++)
        for (v = 0; v < V; v++)
            rGraph[u][v] = graph[u][v];
     
    // This array is filled by BFS and to store path
    int []parent = new int[V];
 
    int max_flow = 0; // There is no flow initially
 
    // Augment the flow while there is path
    // from source to sink
    while (bfs(rGraph, s, t, parent))
    {
        // Find minimum residual capacity of the edges
        // along the path filled by BFS. Or we can say
        // find the maximum flow through the path found.
        int path_flow = Integer.MAX_VALUE;
 
        for (v = t; v != s; v = parent[v])
        {
            u = parent[v];
            path_flow = Math.min(path_flow, rGraph[u][v]);
        }
 
        // update residual capacities of the edges and
        // reverse edges along the path
        for (v = t; v != s; v = parent[v])
        {
            u = parent[v];
            rGraph[u][v] -= path_flow;
            rGraph[v][u] += path_flow;
        }
 
        // Add path flow to overall flow
        max_flow += path_flow;
    }
 
    // Return the overall flow (max_flow is equal to
    // maximum number of edge-disjoint paths)
    return max_flow;
}
 
// Driver Code
public static void main(String[] args)
{
    // Let us create a graph shown in the above example
    int graph[][] = {{0, 1, 1, 1, 0, 0, 0, 0},
                     {0, 0, 1, 0, 0, 0, 0, 0},
                     {0, 0, 0, 1, 0, 0, 1, 0},
                     {0, 0, 0, 0, 0, 0, 1, 0},
                     {0, 0, 1, 0, 0, 0, 0, 1},
                     {0, 1, 0, 0, 0, 0, 0, 1},
                      {0, 0, 0, 0, 0, 1, 0, 1},
                     {0, 0, 0, 0, 0, 0, 0, 0}};
 
    int s = 0;
    int t = 7;
    System.out.println("There can be maximum " +
                findDisjointPaths(graph, s, t) +
                  " edge-disjoint paths from " +
                                 s + " to "+ t);
}
}
 
// This code is contributed by PrinciRaj1992


Python
# Python program to find maximum number of edge disjoint paths
# Complexity : (E*(V^3))
# Total augmenting path = VE
# and BFS with adj matrix takes :V^2 times
  
from collections import defaultdict
  
#This class represents a directed graph using
# adjacency matrix representation
class Graph:
  
    def __init__(self,graph):
        self.graph = graph # residual graph
        self. ROW = len(graph)
         
  
    '''Returns true if there is a path from source 's' to sink 't' in
    residual graph. Also fills parent[] to store the path '''
    def BFS(self,s, t, parent):
 
        # Mark all the vertices as not visited
        visited =[False]*(self.ROW)
         
        # Create a queue for BFS
        queue=[]
         
        # Mark the source node as visited and enqueue it
        queue.append(s)
        visited[s] = True
          
         # Standard BFS Loop
        while queue:
 
            #Dequeue a vertex from queue and print it
            u = queue.pop(0)
         
            # Get all adjacent vertices of the dequeued vertex u
            # If a adjacent has not been visited, then mark it
            # visited and enqueue it
            for ind, val in enumerate(self.graph[u]):
                if visited[ind] == False and val > 0 :
                    queue.append(ind)
                    visited[ind] = True
                    parent[ind] = u
 
        # If we reached sink in BFS starting from source, then return
        # true, else false
        return True if visited[t] else False
             
     
    # Returns the maximum number of edge-disjoint paths from
    #s to t in the given graph
    def findDisjointPaths(self, source, sink):
 
        # This array is filled by BFS and to store path
        parent = [-1]*(self.ROW)
 
        max_flow = 0 # There is no flow initially
 
        # Augment the flow while there is path from source to sink
        while self.BFS(source, sink, parent) :
 
            # Find minimum residual capacity of the edges along the
            # path filled by BFS. Or we can say find the maximum flow
            # through the path found.
            path_flow = float("Inf")
            s = sink
            while(s !=  source):
                path_flow = min (path_flow, self.graph[parent[s]][s])
                s = parent[s]
 
            # Add path flow to overall flow
            max_flow +=  path_flow
 
            # update residual capacities of the edges and reverse edges
            # along the path
            v = sink
            while(v !=  source):
                u = parent[v]
                self.graph[u][v] -= path_flow
                self.graph[v][u] += path_flow
                v = parent[v]
 
        return max_flow
 
  
# Create a graph given in the above diagram
 
graph = [[0, 1, 1, 1, 0, 0, 0, 0],
        [0, 0, 1, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0, 1, 0],
        [0, 0, 0, 0, 0, 0, 1, 0],
        [0, 0, 1, 0, 0, 0, 0, 1],
        [0, 1, 0, 0, 0, 0, 0, 1],
        [0, 0, 0, 0, 0, 1, 0, 1],
        [0, 0, 0, 0, 0, 0, 0, 0]]
  
 
g = Graph(graph)
 
source = 0; sink = 7
  
print ("There can be maximum %d edge-disjoint paths from %d to %d" %
            (g.findDisjointPaths(source, sink), source, sink))
 
 
# This code is contributed by Neelam Yadav


C#
// C# program to find maximum number
// of edge disjoint paths
using System;
using System.Collections.Generic;
 
class GFG
{
 
// Number of vertices in given graph
static int V = 8;
 
/* Returns true if there is a path from
source 's' to sink 't' in residual graph.
Also fills parent[] to store the path */
static bool bfs(int [,]rGraph, int s,
                int t, int []parent)
{
    // Create a visited array and
    // mark all vertices as not visited
    bool []visited = new bool[V];
 
    // Create a queue, enqueue source vertex
    // and mark source vertex as visited
    Queue  q = new Queue ();
    q.Enqueue(s);
    visited[s] = true;
    parent[s] = -1;
 
    // Standard BFS Loop
    while (q.Count != 0)
    {
        int u = q.Peek();
        q.Dequeue();
 
        for (int v = 0; v < V; v++)
        {
            if (visited[v] == false &&
                rGraph[u, v] > 0)
            {
                q.Enqueue(v);
                parent[v] = u;
                visited[v] = true;
            }
        }
    }
 
    // If we reached sink in BFS
    // starting from source, then
    // return true, else false
    return (visited[t] == true);
}
 
// Returns the maximum number of edge-disjoint
// paths from s to t. This function is copy of
// forFulkerson() discussed at http://goo.gl/wtQ4Ks
static int findDisjointPaths(int [,]graph,
                             int s, int t)
{
    int u, v;
 
    // Create a residual graph and fill the
    // residual graph with given capacities
    // in the original graph as residual capacities
    // in residual graph
     
    // Residual graph where rGraph[i,j] indicates
    // residual capacity of edge from i to j (if there
    // is an edge. If rGraph[i,j] is 0, then there is not)
    int [,]rGraph = new int[V, V];
    for (u = 0; u < V; u++)
        for (v = 0; v < V; v++)
            rGraph[u, v] = graph[u, v];
     
    // This array is filled by BFS and
    // to store path
    int []parent = new int[V];
 
    int max_flow = 0; // There is no flow initially
 
    // Augment the flow while there is path
    // from source to sink
    while (bfs(rGraph, s, t, parent))
    {
        // Find minimum residual capacity of the edges
        // along the path filled by BFS. Or we can say
        // find the maximum flow through the path found.
        int path_flow = int.MaxValue;
 
        for (v = t; v != s; v = parent[v])
        {
            u = parent[v];
            path_flow = Math.Min(path_flow,
                                 rGraph[u, v]);
        }
 
        // update residual capacities of the edges
        // and reverse edges along the path
        for (v = t; v != s; v = parent[v])
        {
            u = parent[v];
            rGraph[u, v] -= path_flow;
            rGraph[v, u] += path_flow;
        }
 
        // Add path flow to overall flow
        max_flow += path_flow;
    }
 
    // Return the overall flow (max_flow is equal to
    // maximum number of edge-disjoint paths)
    return max_flow;
}
 
// Driver Code
public static void Main(String[] args)
{
    // Let us create a graph shown
    // in the above example
    int [,]graph = {{0, 1, 1, 1, 0, 0, 0, 0},
                    {0, 0, 1, 0, 0, 0, 0, 0},
                    {0, 0, 0, 1, 0, 0, 1, 0},
                    {0, 0, 0, 0, 0, 0, 1, 0},
                    {0, 0, 1, 0, 0, 0, 0, 1},
                    {0, 1, 0, 0, 0, 0, 0, 1},
                    {0, 0, 0, 0, 0, 1, 0, 1},
                    {0, 0, 0, 0, 0, 0, 0, 0}};
 
    int s = 0;
    int t = 7;
    Console.WriteLine("There can be maximum " +
               findDisjointPaths(graph, s, t) +
                 " edge-disjoint paths from " +
                                s + " to "+ t);
}
}
 
// This code is contributed by Rajput-Ji


Javascript


输出:

There can be maximum 2 edge-disjoint paths from 0 to 7 

时间复杂度:与 Ford-Fulkerson 的 Edmonds-Karp 实现的时间复杂度相同(参见此处讨论的时间复杂度)