删除边以最小化子树和差异
给定一个无向树,其每个节点都与一个权重相关联。我们需要删除一条边,以使一个子树中的权重总和与另一子树中的权重总和之间的差异最小化。
例子:
In above tree,
We have 6 choices for edge deletion,
edge 0-1, subtree sum difference = 21 - 2 = 19
edge 0-2, subtree sum difference = 14 - 9 = 5
edge 0-3, subtree sum difference = 15 - 8 = 7
edge 2-4, subtree sum difference = 20 - 3 = 17
edge 2-5, subtree sum difference = 18 - 5 = 13
edge 3-6, subtree sum difference = 21 - 2 = 19
我们可以使用 DFS 解决这个问题。一个简单的解决方案是逐个删除每条边并检查子树和差异。最后选择其中的最小值。这种方法需要二次方的时间。一种有效的方法可以通过使用树的总和计算两个子树的总和,在线性时间内解决这个问题。我们可以通过从树的总和中减去一个子树的总和来得到另一棵树的总和,这样可以在 O(1) 时间内计算每个节点的子树和差。首先我们计算完整树的权重,然后在对每个节点进行 DFS 的同时,计算它的子树和,通过这两个值我们可以计算子树和的差值。
在下面的代码中,另一个数组子树用于在 subtree[i] 中存储以节点 i 为根的子树的总和。每次都使用当前节点索引和父索引调用 DFS,以仅在每个节点上循环子节点。
请参阅下面的代码以更好地理解。
C++
// C++ program to minimize subtree sum
// difference by one edge deletion
#include
using namespace std;
/* DFS method to traverse through edges,
calculating subtree sum at each node and
updating the difference between subtrees */
void dfs(int u, int parent, int totalSum,
vector edge[], int subtree[], int& res)
{
int sum = subtree[u];
/* loop for all neighbors except parent and
aggregate sum over all subtrees */
for (int i = 0; i < edge[u].size(); i++)
{
int v = edge[u][i];
if (v != parent)
{
dfs(v, u, totalSum, edge, subtree, res);
sum += subtree[v];
}
}
// store sum in current node's subtree index
subtree[u] = sum;
/* at one side subtree sum is 'sum' and other side
subtree sum is 'totalSum - sum' so their difference
will be totalSum - 2*sum, by which we'll update
res */
if (u != 0 && abs(totalSum - 2*sum) < res)
res = abs(totalSum - 2*sum);
}
// Method returns minimum subtree sum difference
int getMinSubtreeSumDifference(int vertex[],
int edges[][2], int N)
{
int totalSum = 0;
int subtree[N];
// Calculating total sum of tree and initializing
// subtree sum's by vertex values
for (int i = 0; i < N; i++)
{
subtree[i] = vertex[i];
totalSum += vertex[i];
}
// filling edge data structure
vector edge[N];
for (int i = 0; i < N - 1; i++)
{
edge[edges[i][0]].push_back(edges[i][1]);
edge[edges[i][1]].push_back(edges[i][0]);
}
int res = INT_MAX;
// calling DFS method at node 0, with parent as -1
dfs(0, -1, totalSum, edge, subtree, res);
return res;
}
// Driver code to test above methods
int main()
{
int vertex[] = {4, 2, 1, 6, 3, 5, 2};
int edges[][2] = {{0, 1}, {0, 2}, {0, 3},
{2, 4}, {2, 5}, {3, 6}};
int N = sizeof(vertex) / sizeof(vertex[0]);
cout << getMinSubtreeSumDifference(vertex, edges, N);
return 0;
}
Java
// Java program to minimize subtree sum
// difference by one edge deletion
import java.util.ArrayList;
class Graph{
static int res;
// DFS method to traverse through edges,
// calculating subtree sum at each node
// and updating the difference between subtrees
static void dfs(int u, int parent, int totalSum,
ArrayList[] edge, int subtree[])
{
int sum = subtree[u];
// Loop for all neighbors except parent
// and aggregate sum over all subtrees
for(int i = 0; i < edge[u].size(); i++)
{
int v = edge[u].get(i);
if (v != parent)
{
dfs(v, u, totalSum, edge, subtree);
sum += subtree[v];
}
}
// Store sum in current node's subtree index
subtree[u] = sum;
// At one side subtree sum is 'sum' and other
// side subtree sum is 'totalSum - sum' so
// their difference will be totalSum - 2*sum,
// by which we'll update res
if (u != 0 && Math.abs(totalSum - 2 * sum) < res)
res = Math.abs(totalSum - 2 * sum);
}
// Method returns minimum subtree sum difference
static int getMinSubtreeSumDifference(int vertex[],
int[][] edges,
int N)
{
int totalSum = 0;
int[] subtree = new int[N];
// Calculating total sum of tree and
// initializing subtree sum's by
// vertex values
for(int i = 0; i < N; i++)
{
subtree[i] = vertex[i];
totalSum += vertex[i];
}
// Filling edge data structure
@SuppressWarnings("unchecked")
ArrayList[] edge = new ArrayList[N];
for(int i = 0; i < N; i++)
{
edge[i] = new ArrayList<>();
}
for(int i = 0; i < N - 1; i++)
{
edge[edges[i][0]].add(edges[i][1]);
edge[edges[i][1]].add(edges[i][0]);
}
// int res = Integer.MAX_VALUE;
// Calling DFS method at node 0, with
// parent as -1
dfs(0, -1, totalSum, edge, subtree);
return res;
}
// Driver code
public static void main(String[] args)
{
res = Integer.MAX_VALUE;
int[] vertex = { 4, 2, 1, 6, 3, 5, 2 };
int[][] edges = { { 0, 1 }, { 0, 2 },
{ 0, 3 }, { 2, 4 },
{ 2, 5 }, { 3, 6 } };
int N = vertex.length;
System.out.println(getMinSubtreeSumDifference(
vertex, edges, N));
}
}
// This code is contributed by sanjeev2552
Python3
# Python3 program to minimize subtree
# Sum difference by one edge deletion
# DFS method to traverse through edges,
# calculating subtree Sum at each node and
# updating the difference between subtrees
def dfs(u, parent, totalSum, edge,
subtree, res):
Sum = subtree[u]
# loop for all neighbors except parent
# and aggregate Sum over all subtrees
for i in range(len(edge[u])):
v = edge[u][i]
if (v != parent):
dfs(v, u, totalSum, edge,
subtree, res)
Sum += subtree[v]
# store Sum in current node's
# subtree index
subtree[u] = Sum
# at one side subtree Sum is 'Sum' and
# other side subtree Sum is 'totalSum - Sum'
# so their difference will be totalSum - 2*Sum,
# by which we'll update res
if (u != 0 and abs(totalSum - 2 * Sum) < res[0]):
res[0] = abs(totalSum - 2 * Sum)
# Method returns minimum subtree
# Sum difference
def getMinSubtreeSumDifference(vertex, edges, N):
totalSum = 0
subtree = [None] * N
# Calculating total Sum of tree
# and initializing subtree Sum's
# by vertex values
for i in range(N):
subtree[i] = vertex[i]
totalSum += vertex[i]
# filling edge data structure
edge = [[] for i in range(N)]
for i in range(N - 1):
edge[edges[i][0]].append(edges[i][1])
edge[edges[i][1]].append(edges[i][0])
res = [999999999999]
# calling DFS method at node 0,
# with parent as -1
dfs(0, -1, totalSum, edge, subtree, res)
return res[0]
# Driver Code
if __name__ == '__main__':
vertex = [4, 2, 1, 6, 3, 5, 2]
edges = [[0, 1], [0, 2], [0, 3],
[2, 4], [2, 5], [3, 6]]
N = len(vertex)
print(getMinSubtreeSumDifference(vertex,
edges, N))
# This code is contributed by PranchalK
C#
// C# program to minimize subtree sum
// difference by one edge deletion
using System;
using System.Collections.Generic;
public class Graph{
static int res;
// DFS method to traverse through edges,
// calculating subtree sum at each node
// and updating the difference between subtrees
static void dfs(int u, int parent, int totalSum,
List[] edge, int []subtree)
{
int sum = subtree[u];
// Loop for all neighbors except parent
// and aggregate sum over all subtrees
for(int i = 0; i < edge[u].Count; i++)
{
int v = edge[u][i];
if (v != parent)
{
dfs(v, u, totalSum, edge, subtree);
sum += subtree[v];
}
}
// Store sum in current node's subtree index
subtree[u] = sum;
// At one side subtree sum is 'sum' and other
// side subtree sum is 'totalSum - sum' so
// their difference will be totalSum - 2*sum,
// by which we'll update res
if (u != 0 && Math.Abs(totalSum - 2 * sum) < res)
res = Math.Abs(totalSum - 2 * sum);
}
// Method returns minimum subtree sum difference
static int getMinSubtreeSumDifference(int []vertex,
int[,] edges,
int N)
{
int totalSum = 0;
int[] subtree = new int[N];
// Calculating total sum of tree and
// initializing subtree sum's by
// vertex values
for(int i = 0; i < N; i++)
{
subtree[i] = vertex[i];
totalSum += vertex[i];
}
// Filling edge data structure
List[] edge = new List[N];
for(int i = 0; i < N; i++)
{
edge[i] = new List();
}
for(int i = 0; i < N - 1; i++)
{
edge[edges[i,0]].Add(edges[i,1]);
edge[edges[i,1]].Add(edges[i,0]);
}
// int res = int.MaxValue;
// Calling DFS method at node 0, with
// parent as -1
dfs(0, -1, totalSum, edge, subtree);
return res;
}
// Driver code
public static void Main(String[] args)
{
res = int.MaxValue;
int[] vertex = { 4, 2, 1, 6, 3, 5, 2 };
int[,] edges = { { 0, 1 }, { 0, 2 },
{ 0, 3 }, { 2, 4 },
{ 2, 5 }, { 3, 6 } };
int N = vertex.Length;
Console.WriteLine(getMinSubtreeSumDifference(
vertex, edges, N));
}
}
// This code is contributed by aashish1995.
Javascript
输出:
5