📌  相关文章
📜  要反转以建立从源到目标的路径的最小边

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

给定一个有向图以及一个源节点和目标节点,我们需要找出需要反转多少条边,以便至少有 1 条从源节点到目标节点的路径。

例子:

In above graph there were two paths from node 0 to node 6,
0 -> 1 -> 2 -> 3 -> 6
0 -> 1 -> 5 -> 4 -> 6
But for first path only two edges need to be reversed, so answer will be 2 only.

假设给定图形的不同版本,可以解决这个问题。在这个版本中,我们制作了一条与每条边相对应的反向边,并为其分配权重 1,并为原始边分配权重 0。上图修改后如下图所示,

现在我们可以看到我们已经修改了图形,如果我们向原始边移动,则不会产生成本,但如果我们向反向边移动 1 成本会增加。因此,如果我们将 Dijkstra 的最短路径应用到这个修改后的图上,从给定的源,那么这将使我们达到从源到目的地的最小成本,即从源到目的地的最小边反转。

以下是基于上述概念的代码。

C++
// C++ Program to find minimum edge reversal to get
// atleast one path from source to destination
#include
using namespace std;
# define INF 0x3f3f3f3f
 
// This class represents a directed graph using
// adjacency list representation
class Graph
{
    int V;    // No. of vertices
 
    // In a weighted graph, we need to store vertex
    // and weight pair for every edge
    list< pair > *adj;
 
public:
    Graph(int V);  // Constructor
 
    // function to add an edge to graph
    void addEdge(int u, int v, int w);
 
    // returns shortest path from s
    vector shortestPath(int s);
};
 
// Allocates memory for adjacency list
Graph::Graph(int V)
{
    this->V = V;
    adj = new list< pair >[V];
}
 
//  method adds a directed edge from u to v with weight w
void Graph::addEdge(int u, int v, int w)
{
    adj[u].push_back(make_pair(v, w));
}
 
// Prints shortest paths from src to all other vertices
vector Graph::shortestPath(int src)
{
    // Create a set to store vertices that are being
    // prerocessed
    set< pair > setds;
 
    // Create a vector for distances and initialize all
    // distances as infinite (INF)
    vector dist(V, INF);
 
    // Insert source itself in Set and initialize its
    // distance as 0.
    setds.insert(make_pair(0, src));
    dist[src] = 0;
 
    /* Looping till all shortest distance are finalized
       then setds will become empty */
    while (!setds.empty())
    {
        // The first vertex in Set is the minimum distance
        // vertex, extract it from set.
        pair tmp = *(setds.begin());
        setds.erase(setds.begin());
 
        // vertex label is stored in second of pair (it
        // has to be done this way to keep the vertices
        // sorted distance (distance must be first item
        // in pair)
        int u = tmp.second;
 
        // 'i' is used to get all adjacent vertices of a vertex
        list< pair >::iterator i;
        for (i = adj[u].begin(); i != adj[u].end(); ++i)
        {
            // Get vertex label and weight of current adjacent
            // of u.
            int v = (*i).first;
            int weight = (*i).second;
 
            //  If there is shorter path to v through u.
            if (dist[v] > dist[u] + weight)
            {
                /*  If distance of v is not INF then it must be in
                    our set, so removing it and inserting again
                    with updated less distance.
                    Note : We extract only those vertices from Set
                    for which distance is finalized. So for them,
                    we would never reach here.  */
                if (dist[v] != INF)
                    setds.erase(setds.find(make_pair(dist[v], v)));
 
                // Updating distance of v
                dist[v] = dist[u] + weight;
                setds.insert(make_pair(dist[v], v));
            }
        }
    }
    return dist;
}
 
/* method adds reverse edge of each original edge
   in the graph. It gives reverse edge a weight = 1
   and all original edges a weight of 0. Now, the
   length of the shortest path will give us the answer.
   If shortest path is p: it means we used p reverse
   edges in the shortest path. */
Graph modelGraphWithEdgeWeight(int edge[][2], int E, int V)
{
    Graph g(V);
    for (int i = 0; i < E; i++)
    {
        //  original edge : weight 0
        g.addEdge(edge[i][0], edge[i][1], 0);
 
        //  reverse edge : weight 1
        g.addEdge(edge[i][1], edge[i][0], 1);
    }
    return g;
}
 
// Method returns minimum number of edges to be
// reversed to reach from src to dest
int getMinEdgeReversal(int edge[][2], int E, int V,
                       int src, int dest)
{
    //  get modified graph with edge weight
    Graph g = modelGraphWithEdgeWeight(edge, E, V);
 
    //  get shortes path vector
    vector dist = g.shortestPath(src);
 
    // If distance of destination is still INF,
    // not possible
    if (dist[dest] == INF)
        return -1;
    else
        return dist[dest];
}
 
//  Driver code to test above method
int main()
{
    int V = 7;
    int edge[][2] = {{0, 1}, {2, 1}, {2, 3}, {5, 1},
                     {4, 5}, {6, 4}, {6, 3}};
    int E = sizeof(edge) / sizeof(edge[0]);
 
    int minEdgeToReverse =
                  getMinEdgeReversal(edge, E, V, 0, 6);
    if (minEdgeToReverse != -1)
        cout << minEdgeToReverse << endl;
    else
        cout << "Not possible" << endl;
    return 0;
}


Java
// Java program to find minimum edge reversal to get
// atleast one path from source to destination
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
 
class Pair
{
    int first, second;
 
    public Pair(int first, int second)
    {
        this.first = first;
        this.second = second;
    }
}
 
// This class represents a directed graph using
// adjacency list representation
class Graph{
     
final int INF = (int)0x3f3f3f3f;
 
// No. of vertices
int V;
 
// In a weighted graph, we need to store vertex
// and weight pair for every edge
List[] adj;
 
// Allocates memory for adjacency list
@SuppressWarnings("unchecked")
public Graph(int V)
{
    this.V = V;
    adj = new ArrayList[V];
 
    for(int i = 0; i < V; i++)
    {
        adj[i] = new ArrayList();
    }
}
 
// Function adds a directed edge from
// u to v with weight w
void addEdge(int u, int v, int w)
{
    adj[u].add(new Pair(v, w));
}
 
// Prints shortest paths from
// src to all other vertices
int[] shortestPath(int src)
{
     
    // Create a set to store vertices
    // that are being prerocessed
    Set setds = new HashSet();
 
    // Create a vector for distances and
    // initialize all distances as infinite(INF)
    int[] dist = new int[V];
    Arrays.fill(dist, INF);
 
    // Insert source itself in Set and initialize
    // its distance as 0.
    setds.add(new Pair(0, src));
    dist[src] = 0;
 
    // Looping till all shortest distance are
    // finalized then setds will become empty
    while (!setds.isEmpty())
    {
         
        // The first vertex in Set is the minimum
        // distance vertex, extract it from set.
        Iterator itr = setds.iterator();
        Pair tmp = itr.next();
        itr.remove();
 
        // Vertex label is stored in second of pair (it
        // has to be done this way to keep the vertices
        // sorted distance (distance must be first item
        // in pair)
        int u = tmp.second;
 
        // 'i' is used to get all adjacent
        // vertices of a vertex
        for(Pair p : adj[u])
        {
             
            // Get vertex label and weight of
            // current adjacent of u.
            int v = p.first;
            int weight = p.second;
 
            // If there is shorter path to v through u.
            if (dist[v] > dist[u] + weight)
            {
                 
                // If distance of v is not INF then it
                // must be in our set, so removing it
                // and inserting again with updated
                // less distance. Note : We extract
                // only those vertices from Set for
                // which distance is finalized. So
                // for them, we would never reach here.
                if (dist[v] != INF)
                {
                    setds.remove(new Pair(dist[v], v));
                }
                 
                // setds.erase(setds.find(new Pair(dist[v], v)));
 
                // Updating distance of v
                dist[v] = dist[u] + weight;
                setds.add(new Pair(dist[v], v));
            }
        }
    }
    return dist;
}
}
 
class GFG{
static final int INF = (int)0x3f3f3f3f;
 
// Function adds reverse edge of each original
// edge in the graph. It gives reverse edge
// a weight = 1 and all original edges a
// weight of 0. Now, the length of the
// shortest path will give us the answer.
// If shortest path is p: it means we
// used p reverse edges in the shortest path.
static Graph modelGraphWithEdgeWeight(int edge[][],
                                      int E, int V)
{
    Graph g = new Graph(V);
    for(int i = 0; i < E; i++)
    {
         
        // Original edge : weight 0
        g.addEdge(edge[i][0], edge[i][1], 0);
 
        // Reverse edge : weight 1
        g.addEdge(edge[i][1], edge[i][0], 1);
    }
    return g;
}
 
// Function returns minimum number of edges to be
// reversed to reach from src to dest
static int getMinEdgeReversal(int edge[][], int E,
                              int V, int src, int dest)
{
     
    // Get modified graph with edge weight
    Graph g = modelGraphWithEdgeWeight(edge, E, V);
 
    // Get shortes path vector
    int[] dist = g.shortestPath(src);
 
    // If distance of destination is still INF,
    // not possible
    if (dist[dest] == INF)
        return -1;
    else
        return dist[dest];
}
 
// Driver code
public static void main(String[] args)
{
    int V = 7;
    int edge[][] = { { 0, 1 }, { 2, 1 },
                     { 2, 3 }, { 5, 1 },
                     { 4, 5 }, { 6, 4 },
                     { 6, 3 } };
    int E = edge.length;
 
    int minEdgeToReverse = getMinEdgeReversal(
        edge, E, V, 0, 6);
     
    if (minEdgeToReverse != -1)
        System.out.println(minEdgeToReverse);
    else
        System.out.println("Not possible");
}
}
 
// This code is contributed by sanjeev2552


Python3
# Python3 Program to find minimum edge reversal to get
# atleast one path from source to destination
 
# method adds a directed edge from u to v with weight w
def addEdge(u, v, w):
    global adj
    adj[u].append((v, w))
 
# Prints shortest paths from src to all other vertices
def shortestPath(src):
   
    # Create a set to store vertices that are being
    # prerocessed
    setds = {}
 
    # Create a vector for distances and initialize all
    # distances as infinite (INF)
    dist = [10**18 for i in range(V)]
 
    # Insert source itself in Set and initialize its
    global adj
    setds[(0, src)] = 1
    dist[src] = 0
 
    # /* Looping till all shortest distance are finalized
 
    # then setds will become empty */
    while (len(setds) > 0):
       
        # The first vertex in Set is the minimum distance
        # vertex, extract it from set.
        tmp = list(setds.keys())[0]
        del setds[tmp]
 
        # vertex label is stored in second of pair (it
        # has to be done this way to keep the vertices
        # sorted distance (distance must be first item
        # in pair)
        u = tmp[1]
 
        # 'i' is used to get all adjacent vertices of a vertex
        # list< pair >::iterator i;
        for i in adj[u]:
           
            # Get vertex label and weight of current adjacent
            # of u.
            v = i[0];
            weight = i[1]
 
            # If there is shorter path to v through u.
            if (dist[v] > dist[u] + weight):
               
                # /* If distance of v is not INF then it must be in
                #     our set, so removing it and inserting again
                #     with updated less distance.
                #     Note : We extract only those vertices from Set
                #     for which distance is finalized. So for them,
                #     we would never reach here. */
                if (dist[v] != 10**18):
                    del setds[(dist[v], v)]
 
                # Updating distance of v
                dist[v] = dist[u] + weight
                setds[(dist[v], v)] = 1
 
    return dist
 
# /* method adds reverse edge of each original edge
# in the graph. It gives reverse edge a weight = 1
# and all original edges a weight of 0. Now, the
# length of the shortest path will give us the answer.
# If shortest path is p: it means we used p reverse
# edges in the shortest path. */
def modelGraphWithEdgeWeight(edge, E, V):
    global adj
    for i in range(E):
       
        # original edge : weight 0
        addEdge(edge[i][0], edge[i][1], 0)
 
        # reverse edge : weight 1
        addEdge(edge[i][1], edge[i][0], 1)
 
# Method returns minimum number of edges to be
# reversed to reach from src to dest
def getMinEdgeReversal(edge, E, V,src, dest):
   
    # get modified graph with edge weight
    modelGraphWithEdgeWeight(edge, E, V)
 
    # get shortes path vector
    dist = shortestPath(src)
 
    # If distance of destination is still INF,
    # not possible
    if (dist[dest] == 10**18):
        return -1
    else:
        return dist[dest]
 
# Driver code
if __name__ == '__main__':
    V = 7
    edge = [[0, 1], [2, 1], [2, 3], [5, 1],[4, 5], [6, 4], [6, 3]]
    E, adj = len(edge), [[] for i in range(V + 1)]
    minEdgeToReverse = getMinEdgeReversal(edge, E, V, 0, 6)
    if (minEdgeToReverse != -1):
        print(minEdgeToReverse)
    else:
        print("Not possible")
 
        # This code is contributed by mohit kumar 29


输出:

2

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