给定一棵具有与每个节点相关联的值的N元树,任务是选择这些节点的子集,以使所选节点的总和在不应该直接连接子集中的两个所选节点的约束下达到最大。我们在总和中取了一个节点,那么我们就不能考虑它的任何子节点,反之亦然。
例子:
上图选择深绿色的节点以获取最大值25。
在上一篇文章中使用递归讨论了解决此问题的方法。
在本文中,我们将讨论在树上使用动态编程的方法。
解决问题时,会出现两种情况:
- 对于特定节点,可以通过将节点本身以及其子树中的节点包括在内来计算最大总和。
- 或者,最大总和是通过排除当前节点并仅包括其子树中的节点来计算的。
让我们假设:
- 通过从该节点的子树中选择节点(也包括该节点),将dp1 [node]设为最大可能的总和。
- 并且,通过从节点的子树中选择节点,并且不包括节点本身,dp2 [node]将成为最大可能的总和。
在第一种情况下,如果我们包括当前节点,则将其值相加,然后我们将不包括其任何直接子节点,因此所有子节点的dp2 []的总和将被计入计数以计算dp1 [节点]。那是,
dp1[node] = tree[node] + sum(dp2[children1], dp2[children2], …)
在第二种情况下,如果不包括当前节点,则不添加其值,但是可以采用子节点,也可以不采用子节点,因此将所有子节点的最大值之和计入计数以计算dp2 [node]。那是,
dp2[node] = tree[node] + sum(max(dp1[children1], dp2[children1]), max(dp1[children2], dp2[children2])…)
最后,最终答案将是dp1 [root]和dp2 [root]的最大值。
下面是上述方法的实现:
C++
// C++ program to find maximum sum
// of a subset of nodes that are not adjacent
#include
using namespace std;
// Function to find the diameter of the tree
// using Dynamic Programming
void dfs(int node, int parent, int dp1[], int dp2[],
list* adj, int tree[])
{
int sum1 = 0, sum2 = 0;
// Traverse for all children of node
for (auto i = adj[node].begin(); i != adj[node].end(); ++i) {
if (*i == parent)
continue;
// Call DFS function again
dfs(*i, node, dp1, dp2, adj, tree);
// Include the current node
// then donot include the children
sum1 += dp2[*i];
// Donot include current node,
// then include children or not include them
sum2 += max(dp1[*i], dp2[*i]);
}
// Recurrence value
dp1[node] = tree[node] + sum1;
dp2[node] = sum2;
}
/* Driver program to test above functions */
int main()
{
int n = 5;
/* Constructed tree is
1
/ \
2 3
/ \
4 5 */
list* adj = new list[n + 1];
/* create undirected edges */
adj[1].push_back(2);
adj[2].push_back(1);
adj[1].push_back(3);
adj[3].push_back(1);
adj[2].push_back(4);
adj[4].push_back(2);
adj[2].push_back(5);
adj[5].push_back(2);
// Numbers to node
int tree[n + 1];
tree[1] = 10;
tree[2] = 5;
tree[3] = 11;
tree[4] = 6;
tree[5] = 8;
int dp1[n + 1], dp2[n + 1];
memset(dp1, 0, sizeof dp1);
memset(dp2, 0, sizeof dp2);
dfs(1, 1, dp1, dp2, adj, tree);
// Find maximum sum by calling function
cout << "Maximum sum: "
<< max(dp1[1], dp2[1]) << endl;
return 0;
}
Python3
# Python3 program to find
# maximum sum of a subset
# of nodes that are not
# adjacent
# Function to find the diameter
# of the tree using Dynamic
# Programming
def dfs(node, parent, dp1,
dp2, adj, tree):
sum1 = 0
sum2 = 0
# Traverse for all
# children of node
for i in adj[node]:
if (i == parent):
continue;
# Call DFS function
# again
dfs(i, node, dp1,
dp2, adj, tree);
# Include the current
# node then donot include
# the children
sum1 += dp2[i];
# Donot include current node,
# then include children or not
# include them
sum2 += max(dp1[i],
dp2[i]);
# Recurrence value
dp1[node] = tree[node] + sum1;
dp2[node] = sum2;
# Driver code
if __name__=="__main__":
n = 5;
''' Constructed tree is
1
/ \
2 3
/ \
4 5 '''
adj = [[] for i in range(n + 1)]
# create undirected edges
adj[1].append(2);
adj[2].append(1);
adj[1].append(3);
adj[3].append(1);
adj[2].append(4);
adj[4].append(2);
adj[2].append(5);
adj[5].append(2);
# Numbers to node
tree = [0 for i in range(n + 1)];
tree[1] = 10;
tree[2] = 5;
tree[3] = 11;
tree[4] = 6;
tree[5] = 8;
dp1 = [0 for i in range(n + 1)];
dp2 = [0 for i in range(n + 1)];
dfs(1, 1, dp1, dp2, adj, tree);
# Find maximum sum by calling
# function
print("Maximum sum:",
max(dp1[1], dp2[1]))
# This code is contributed by Rutvik_56
C#
// C# program to find maximum sum
// of a subset of nodes that are not adjacent
using System;
using System.Collections;
class GFG
{
// Function to find the diameter of the tree
// using Dynamic Programming
public static void dfs(int node, int parent, int []dp1, int []dp2,
ArrayList []adj, int []tree)
{
int sum1 = 0, sum2 = 0;
// Traverse for all children of node
foreach(int i in adj[node])
{
if (i == parent)
continue;
// Call DFS function again
dfs(i, node, dp1, dp2, adj, tree);
// Include the current node
// then donot include the children
sum1 += dp2[i];
// Donot include current node,
// then include children or not include them
sum2 += Math.Max(dp1[i], dp2[i]);
}
// Recurrence value
dp1[node] = tree[node] + sum1;
dp2[node] = sum2;
}
/* Driver program to test above functions */
public static void Main(string []arg)
{
int n = 5;
/* Constructed tree is
1
/ \
2 3
/ \
4 5 */
ArrayList []adj = new ArrayList[n + 1];
for(int i = 0; i < n + 1; i++)
{
adj[i] = new ArrayList();
}
/* create undirected edges */
adj[1].Add(2);
adj[2].Add(1);
adj[1].Add(3);
adj[3].Add(1);
adj[2].Add(4);
adj[4].Add(2);
adj[2].Add(5);
adj[5].Add(2);
// Numbers to node
int []tree = new int[n + 1];
tree[1] = 10;
tree[2] = 5;
tree[3] = 11;
tree[4] = 6;
tree[5] = 8;
int []dp1 = new int[n + 1];
int []dp2 = new int[n + 1];
Array.Fill(dp1, 0);
Array.Fill(dp2, 0);
dfs(1, 1, dp1, dp2, adj, tree);
// Find maximum sum by calling function
Console.Write("Maximum sum: "+ Math.Max(dp1[1], dp2[1]));
}
}
// This code is contributed by pratham76
输出:
Maximum sum: 25