📌  相关文章
📜  删除边以最小化子树和差异

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

删除边以最小化子树和差异

给定一个无向树,其每个节点都与一个权重相关联。我们需要删除一条边,以使一个子树中的权重总和与另一子树中的权重总和之间的差异最小化。

例子:

删除边以最小化子树和差异

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