📜  生成根的最小边反转

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

生成根的最小边反转

给定一棵有 V 个顶点和 V-1 条边的有向树,我们需要选择这样一个根(从我们可以到达的给定节点到每个其他节点),边反转的次数最少。

例子:

生成根的最小边反转

In above tree, if we choose node 3 as our 
root then we need to reverse minimum number
of 3 edges to reach every other node, 
changed tree is shown on the right side.
 

我们可以使用 DFS 解决这个问题。我们在给定树的任何随机节点处开始 dfs 并在每个节点存储它与起始节点的距离,假设所有边都是无向的,我们还存储需要在从起始节点到当前节点的路径中反转的边数,让我们表示像后边这样的边,所以后边是指向路径中节点的边。有了这个 dfs,我们还计算了树中边缘反转的总数。在这个计算之后,在每个节点,我们可以计算“到达每个其他节点的边反转数”,如下所示,
Let total number of reversals in tree when some node is chosen as starting node for dfs is R then if we want to reach every other node from node i we need to reverse all back edges from path node i to starting node and we also need to将节点 i 以外的所有其他后边反转到起始节点路径。第一部分将是(节点 i 到起始节点的距离 - 节点 i 的后边数)因为我们想要反转从节点 i 到起始节点的路径中的边,它将是总边(即距离)减去从起始节点到的后边节点 i(即节点 i 的后边计数)。第二部分将是(树 R 的总边缘反转或总后边缘 - 节点 i 的后边缘计数)。在每个节点计算这个值之后,我们将选择它们中的最小值作为我们的结果。

在下面的代码中,在给定的边缘方向添加权重 0,并在反向方向添加权重 1,用于计算 dfs 方法中的反转边缘。

C++
// C++ program to find min edge reversal to
// make every node reachable from root
#include 
using namespace std;
  
// method to dfs in tree and populates disRev values
int dfs(vector< pair > g[],
        pair disRev[], bool visit[], int u)
{
    // visit current node
    visit[u] = true;
    int totalRev = 0;
  
    // looping over all neighbors
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i].first;
        if (!visit[v])
        {
            // distance of v will be one more than distance of u
            disRev[v].first = disRev[u].first + 1;
  
            // initialize back edge count same as
            // parent node's count
            disRev[v].second = disRev[u].second;
  
            // if there is a reverse edge from u to i,
            // then only update
            if (g[u][i].second)
            {
                disRev[v].second = disRev[u].second + 1;
                totalRev++;
            }
            totalRev += dfs(g, disRev, visit, v);
        }
    }
  
    // return total reversal in subtree rooted at u
    return totalRev;
}
  
// method prints root and minimum number of edge reversal
void printMinEdgeReverseForRootNode(int edges[][2], int e)
{
    // number of nodes are one more than number of edges
    int V = e + 1;
  
    // data structure to store directed tree
    vector< pair > g[V];
  
    // disRev stores two values - distance and back
    // edge count from root node
    pair disRev[V];
  
    bool visit[V];
  
    int u, v;
    for (int i = 0; i < e; i++)
    {
        u = edges[i][0];
        v = edges[i][1];
  
        // add 0 weight in direction of u to v
        g[u].push_back(make_pair(v, 0));
  
        // add 1 weight in reverse direction
        g[v].push_back(make_pair(u, 1));
    }
  
    //    initialize all variables
    for (int i = 0; i < V; i++)
    {
        visit[i] = false;
        disRev[i].first = disRev[i].second = 0;
    }
  
    int root = 0;
  
    // dfs populates disRev data structure and
    // store total reverse edge counts
    int totalRev = dfs(g, disRev, visit, root);
  
    // UnComment below lines to print each node's
    // distance and edge reversal count from root node
    /*
    for (int i = 0; i < V; i++)
    {
        cout << i << " : " << disRev[i].first
              << " " << disRev[i].second << endl;
    }
    */
  
    int res = INT_MAX;
  
    // loop over all nodes to choose minimum edge reversal
    for (int i = 0; i < V; i++)
    {
        // (reversal in path to i) + (reversal
        // in all other tree parts)
        int edgesToRev = (totalRev - disRev[i].second) +
                         (disRev[i].first - disRev[i].second);
  
        // choose minimum among all values
        if (edgesToRev < res)
        {
            res = edgesToRev;
            root = i;
        }
    }
  
    // print the designated root and total
    // edge reversal made
    cout << root << " " << res << endl;
}
  
// Driver code to test above methods
int main()
{
    int edges[][2] =
    {
        {0, 1},
        {2, 1},
        {3, 2},
        {3, 4},
        {5, 4},
        {5, 6},
        {7, 6}
    };
    int e = sizeof(edges) / sizeof(edges[0]);
  
    printMinEdgeReverseForRootNode(edges, e);
    return 0;
}


Java
// Java program to find min edge reversal to 
// make every node reachable from root 
import java.util.*;
  
class GFG
{
    // pair class
    static class pair
    {
        int first,second;
        pair(int a ,int b)
        {
            first = a;
            second = b;
        }
    }
  
// method to dfs in tree and populates disRev values 
static int dfs(Vector> g, 
        pair disRev[], boolean visit[], int u) 
{ 
    // visit current node 
    visit[u] = true; 
    int totalRev = 0; 
  
    // looping over all neighbors 
    for (int i = 0; i < g.get(u).size(); i++) 
    { 
        int v = g.get(u).get(i).first; 
        if (!visit[v]) 
        { 
            // distance of v will be one more than distance of u 
            disRev[v].first = disRev[u].first + 1; 
  
            // initialize back edge count same as 
            // parent node's count 
            disRev[v].second = disRev[u].second; 
  
            // if there is a reverse edge from u to i, 
            // then only update 
            if (g.get(u).get(i).second!=0) 
            { 
                disRev[v].second = disRev[u].second + 1; 
                totalRev++; 
            } 
            totalRev += dfs(g, disRev, visit, v); 
        } 
    } 
  
    // return total reversal in subtree rooted at u 
    return totalRev; 
} 
  
// method prints root and minimum number of edge reversal 
static void printMinEdgeReverseForRootNode(int edges[][], int e) 
{ 
    // number of nodes are one more than number of edges 
    int V = e + 1; 
  
    // data structure to store directed tree 
    Vector> g=new Vector>();
      
    for(int i = 0; i < V + 1; i++)
    g.add(new Vector());
  
    // disRev stores two values - distance and back 
    // edge count from root node 
    pair disRev[] = new pair[V]; 
  
    for(int i = 0; i < V; i++)
    disRev[i] = new pair(0, 0);
      
    boolean visit[] = new boolean[V]; 
  
    int u, v; 
    for (int i = 0; i < e; i++) 
    { 
        u = edges[i][0]; 
        v = edges[i][1]; 
  
        // add 0 weight in direction of u to v 
        g.get(u).add(new pair(v, 0)); 
  
        // add 1 weight in reverse direction 
        g.get(v).add(new pair(u, 1)); 
    } 
  
    // initialize all variables 
    for (int i = 0; i < V; i++) 
    { 
        visit[i] = false; 
        disRev[i].first = disRev[i].second = 0; 
    } 
  
    int root = 0; 
  
    // dfs populates disRev data structure and 
    // store total reverse edge counts 
    int totalRev = dfs(g, disRev, visit, root); 
  
    // UnComment below lines to print each node's 
    // distance and edge reversal count from root node 
    /* 
    for (int i = 0; i < V; i++) 
    { 
        cout << i << " : " << disRev[i].first 
            << " " << disRev[i].second << endl; 
    } 
    */
  
    int res = Integer.MAX_VALUE; 
  
    // loop over all nodes to choose minimum edge reversal 
    for (int i = 0; i < V; i++) 
    { 
        // (reversal in path to i) + (reversal 
        // in all other tree parts) 
        int edgesToRev = (totalRev - disRev[i].second) + 
                        (disRev[i].first - disRev[i].second); 
  
        // choose minimum among all values 
        if (edgesToRev < res) 
        { 
            res = edgesToRev; 
            root = i; 
        } 
    } 
  
    // print the designated root and total 
    // edge reversal made 
    System.out.println(root + " " + res ); 
} 
  
// Driver code 
public static void main(String args[])
{ 
    int edges[][] = 
    { 
        {0, 1}, 
        {2, 1}, 
        {3, 2}, 
        {3, 4}, 
        {5, 4}, 
        {5, 6}, 
        {7, 6} 
    }; 
    int e = edges.length; 
  
    printMinEdgeReverseForRootNode(edges, e); 
}
} 
  
// This code is contributed by Arnab Kundu


Python3
# Python3 program to find min edge reversal
# to make every node reachable from root
import sys
  
# Method to dfs in tree and populates 
# disRev values
def dfs(g, disRev, visit, u):
      
    # Visit current node
    visit[u] = True
    totalRev = 0
  
    # Looping over all neighbors
    for i in range(len(g[u])):
        v = g[u][i][0]
          
        if (not visit[v]):
              
            # Distance of v will be one more
            # than distance of u
            disRev[v][0] = disRev[u][0] + 1
  
            # Initialize back edge count same as
            # parent node's count
            disRev[v][1] = disRev[u][1]
  
            # If there is a reverse edge from u to i,
            # then only update
            if (g[u][i][1]):
                disRev[v][1] = disRev[u][1] + 1
                totalRev += 1
                  
            totalRev += dfs(g, disRev, visit, v)
  
    # Return total reversal in subtree rooted at u
    return totalRev
  
# Method prints root and minimum number of
# edge reversal
def printMinEdgeReverseForRootNode(edges, e):
      
    # Number of nodes are one more than
    # number of edges
    V = e + 1
  
    # Data structure to store directed tree
    g = [[] for i in range(V)]
  
    # disRev stores two values - distance
    # and back edge count from root node
    disRev = [[0, 0] for i in range(V)]
  
    visit = [False for i in range(V)]
  
    # u, v
    for i in range(e):
        u = edges[i][0]
        v = edges[i][1]
          
        # Add 0 weight in direction of u to v
        g[u].append([v, 0])
  
        # Add 1 weight in reverse direction
        g[v].append([u, 1])
  
    # Initialize all variables
    for i in range(V):
        visit[i] = False
        disRev[i][0] = disRev[i][1] = 0
  
    root = 0
  
    # dfs populates disRev data structure and
    # store total reverse edge counts
    totalRev = dfs(g, disRev, visit, root)
  
    # UnComment below lines to preach node's
    # distance and edge reversal count from root node
    # for (i = 0 i < V i++)
    # {
    #     cout << i << " : " << disRev[i][0]
    #         << " " << disRev[i][1] << endl
    # }
    res = sys.maxsize
  
    # Loop over all nodes to choose 
    # minimum edge reversal
    for i in range(V):
          
        # (reversal in path to i) + (reversal
        # in all other tree parts)
        edgesToRev = ((totalRev - disRev[i][1]) + 
                  (disRev[i][0] - disRev[i][1]))
  
        # Choose minimum among all values
        if (edgesToRev < res):
            res = edgesToRev
            root = i
  
    # Print the designated root and total
    # edge reversal made
    print(root, res) 
  
# Driver code 
if __name__ == '__main__':
      
    edges = [ [ 0, 1 ], [ 2, 1 ],
              [ 3, 2 ], [ 3, 4 ],
              [ 5, 4 ], [ 5, 6 ],
              [ 7, 6 ] ]
  
    e = len(edges)
  
    printMinEdgeReverseForRootNode(edges, e)
  
# This code is contributed by mohit kumar 29


C#
// C# program to find min edge reversal to 
// make every node reachable from root
using System;
using System.Collections.Generic;
      
class GFG
{
    // pair class
    public class pair
    {
        public int first,second;
        public pair(int a, int b)
        {
            first = a;
            second = b;
        }
    }
  
// method to dfs in tree and populates disRev values 
static int dfs(List> g, 
               pair []disRev, Boolean []visit, int u) 
{ 
    // visit current node 
    visit[u] = true; 
    int totalRev = 0; 
  
    // looping over all neighbors 
    for (int i = 0; i < g[u].Count; i++) 
    { 
        int v = g[u][i].first; 
        if (!visit[v]) 
        { 
            // distance of v will be one more 
            // than distance of u 
            disRev[v].first = disRev[u].first + 1; 
  
            // initialize back edge count same as 
            // parent node's count 
            disRev[v].second = disRev[u].second; 
  
            // if there is a reverse edge from u to i, 
            // then only update 
            if (g[u][i].second != 0) 
            { 
                disRev[v].second = disRev[u].second + 1; 
                totalRev++; 
            } 
            totalRev += dfs(g, disRev, visit, v); 
        } 
    } 
  
    // return total reversal in subtree rooted at u 
    return totalRev; 
} 
  
// method prints root and minimum number of edge reversal 
static void printMinEdgeReverseForRootNode(int [,]edges, int e) 
{ 
    // number of nodes are one more than number of edges 
    int V = e + 1; 
  
    // data structure to store directed tree 
    List> g = new List>();
      
    for(int i = 0; i < V + 1; i++)
    g.Add(new List());
  
    // disRev stores two values - distance and back 
    // edge count from root node 
    pair []disRev = new pair[V]; 
  
    for(int i = 0; i < V; i++)
    disRev[i] = new pair(0, 0);
      
    Boolean []visit = new Boolean[V]; 
  
    int u, v; 
    for (int i = 0; i < e; i++) 
    { 
        u = edges[i, 0]; 
        v = edges[i, 1]; 
  
        // add 0 weight in direction of u to v 
        g[u].Add(new pair(v, 0)); 
  
        // add 1 weight in reverse direction 
        g[v].Add(new pair(u, 1)); 
    } 
  
    // initialize all variables 
    for (int i = 0; i < V; i++) 
    { 
        visit[i] = false; 
        disRev[i].first = disRev[i].second = 0; 
    } 
  
    int root = 0; 
  
    // dfs populates disRev data structure and 
    // store total reverse edge counts 
    int totalRev = dfs(g, disRev, visit, root); 
  
    // UnComment below lines to print each node's 
    // distance and edge reversal count from root node 
    /* 
    for (int i = 0; i < V; i++) 
    { 
        cout << i << " : " << disRev[i].first 
            << " " << disRev[i].second << endl; 
    } 
    */
  
    int res = int.MaxValue; 
  
    // loop over all nodes to choose minimum edge reversal 
    for (int i = 0; i < V; i++) 
    { 
        // (reversal in path to i) + (reversal 
        // in all other tree parts) 
        int edgesToRev = (totalRev - disRev[i].second) + 
                         (disRev[i].first - disRev[i].second); 
  
        // choose minimum among all values 
        if (edgesToRev < res) 
        { 
            res = edgesToRev; 
            root = i; 
        } 
    } 
  
    // print the designated root and total 
    // edge reversal made 
    Console.WriteLine(root + " " + res); 
} 
  
// Driver code 
public static void Main(String []args)
{ 
    int [,]edges = {{0, 1}, {2, 1}, 
                    {3, 2}, {3, 4}, 
                    {5, 4}, {5, 6}, 
                    {7, 6}}; 
    int e = edges.GetLength(0); 
  
    printMinEdgeReverseForRootNode(edges, e); 
}
} 
  
// This code is contributed by 29AjayKumar


Javascript


输出:

3 3