📌  相关文章
📜  使树的所有顶点均为零的最小运算

📅  最后修改于: 2021-05-06 18:53:34             🧑  作者: Mango

给定一棵树,其中每个顶点V都有一个值A [V]存储在其中。任务是找到使树的所有顶点中存储的值等于零所需的最少操作数。

每个操作包括以下两个步骤:

  1. 选择一个子树,使该子树包含顶点1。
  2. 将子树的所有顶点的值增加/减少1。

考虑以下树

注意:顶点中的数字表示顶点数,A [V]表示顶点的值,如上所述。

对于以下树,我们执行以下3个操作以使值成为所有顶点
等于零:

注意:黑色的顶点表示所选的子树。

我们可以使用动态编程解决此问题。

令dp [i] [0]表示选择以i为根的任何子树并且所有顶点的值增加1的操作数。
类似地,dp [i] [1]表示选择以i为根的任何子树并且所有顶点的值都减少1的操作数。

对于所有叶子,如果说叶子节点V使得某个叶子节点U的A [V] = 0,即dp [i] [ 1] = A [V]和dp [i] [0] = 0

现在,如果我们在某个非叶节点中说v,我们看一下它的所有子节点,如果说对V的一个子节点i进行X i次加法运算,那么我们需要对节点的所有子节点i应用max(X i v),增加对任何以v为根的子树的操作。类似地,我们对减少节点V的操作进行相同的操作。

答案是节点1的增加和减少操作的总和,因为这些操作仅应用于具有节点1的子树。

下面是上述方法的实现:

C++
// CPP program to find the Minimum Operations
// to modify values of all tree vertices to zero
#include 
  
using namespace std;
  
// A utility function to add an edge in an
// undirected graph
void addEdge(vector adj[], int u, int v)
{
    adj[u].push_back(v);
    adj[v].push_back(u);
}
  
// A utility function to print the adjacency list
// representation of graph
void printGraph(vector adj[], int V)
{
    for (int v = 0; v < V; ++v) {
        cout << "\n Adjacency list of vertex "
             << v << "\n head ";
        for (auto x : adj[v])
            cout << "-> " << x;
        printf("\n");
    }
}
  
// Utility Function for findMinOperation()
void findMinOperationUtil(int dp[][2], vector adj[],
                          int A[], int src, int parent)
{
    // Base Case for current node
    dp[src][0] = dp[src][1] = 0;
  
    // iterate over the adjacency list for src
    for (auto V : adj[src]) {
        if (V == parent)
            continue;
  
        // calculate DP table for each child V
        findMinOperationUtil(dp, adj, A, V, src);
  
        // Number of Increase Type operations for node src
        // is equal to maximum of number of increase operations
        // required by each of its child
        dp[src][0] = max(dp[src][0], dp[V][0]);
  
        // Number of Decrease Type operations for node src
        // is equal to maximum of number of decrease operations
        // required by each of its child
        dp[src][1] = max(dp[src][1], dp[V][1]);
    }
  
    // After performing operations for subtree rooted at src
    // A[src] changes by the net difference of increase and
    // decrease type operations
    A[src - 1] += dp[src][0] - dp[src][1];
  
    // for negative value of node src
    if (A[src - 1] > 0) {
        dp[src][1] += A[src - 1];
    }
    else {
        dp[src][0] += abs(A[src - 1]);
    }
}
  
// Returns the minimum operations required to make
// value of all vertices equal to zero, uses
// findMinOperationUtil()
int findMinOperation(vector adj[], int A[], int V)
{
  
    // Initialise DP table
    int dp[V + 1][2];
    memset(dp, 0, sizeof dp);
  
    // find dp[1][0] and dp[1][1]
    findMinOperationUtil(dp, adj, A, 1, 0);
  
    int minOperations = dp[1][0] + dp[1][1];
    return minOperations;
}
  
// Driver code
int main()
{
    int V = 5;
  
    // Build the Graph/Tree
    vector adj[V + 1];
    addEdge(adj, 1, 2);
    addEdge(adj, 1, 3);
  
    int A[] = { 1, -1, 1 };
    int minOperations = findMinOperation(adj, A, V);
    cout << minOperations;
  
    return 0;
}


Python3
# Python3 program to find the Minimum Operations 
# to modify values of all tree vertices to zero 
  
# A utility function to add an 
# edge in an undirected graph 
def addEdge(adj, u, v): 
  
    adj[u].append(v) 
    adj[v].append(u) 
  
# A utility function to print the adjacency 
# list representation of graph 
def printGraph(adj, V): 
  
    for v in range(0, V): 
        print("Adjacency list of vertex", v)
        print("head", end = " ")
          
        for x in adj[v]: 
            print("->", x, end = "") 
        print() 
  
# Utility Function for findMinOperation() 
def findMinOperationUtil(dp, adj, A, src, parent): 
  
    # Base Case for current node 
    dp[src][0] = dp[src][1] = 0
  
    # Iterate over the adjacency list for src 
    for V in adj[src]: 
        if V == parent: 
            continue
  
        # calculate DP table for each child V 
        findMinOperationUtil(dp, adj, A, V, src) 
  
        # Number of Increase Type operations for node src 
        # is equal to maximum of number of increase operations 
        # required by each of its child 
        dp[src][0] = max(dp[src][0], dp[V][0]) 
  
        # Number of Decrease Type operations for node 
        # src is equal to maximum of number of decrease 
        # operations required by each of its child 
        dp[src][1] = max(dp[src][1], dp[V][1]) 
      
    # After performing operations for subtree rooted 
    # at src A[src] changes by the net difference of 
    # increase and decrease type operations 
    A[src - 1] += dp[src][0] - dp[src][1] 
  
    # for negative value of node src 
    if A[src - 1] > 0:
        dp[src][1] += A[src - 1] 
      
    else:
        dp[src][0] += abs(A[src - 1]) 
  
# Returns the minimum operations required to 
# make value of all vertices equal to zero, 
# uses findMinOperationUtil() 
def findMinOperation(adj, A, V): 
  
    # Initialise DP table 
    dp = [[0, 0] for i in range(V + 1)] 
  
    # find dp[1][0] and dp[1][1] 
    findMinOperationUtil(dp, adj, A, 1, 0) 
  
    minOperations = dp[1][0] + dp[1][1] 
    return minOperations 
  
# Driver code 
if __name__ == "__main__": 
  
    V = 5
  
    # Build the Graph/Tree 
    adj = [[] for i in range(V + 1)]
    addEdge(adj, 1, 2) 
    addEdge(adj, 1, 3) 
  
    A = [1, -1, 1]
    minOperations = findMinOperation(adj, A, V) 
    print(minOperations) 
  
# This code is contributed by Rituraj Jain


输出:
3

时间复杂度:O(V),其中V是树中的节点数。
辅助空间:O(V),其中V是树中的节点数。