生成根的最小边反转
给定一棵有 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