给定具有与每个节点关联的值的 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
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。