给定n-ary整数树,任务是找到一个子序列的最大总和,其约束条件是序列中没有2个数字应该共享树中的公共边。 例: 1 / \ 2 5 / \ 3 4 最大非相邻和= 3 + 4 + 5 = 12 以下是http://www.geeksforgeeks.org/maximum-sum-such-that-no-two-elements-are-adjacent中列出的算法的错误扩展?
def max_sum(node, inc_sum, exc_sum):
for child in node.children:
exc_new = max(inc_sum, exc_sum)
inc_sum = exc_sum + child.val
exc_sum = exc_new
inc_sum, exc_sum = max(max_sum(child, inc_sum, exc_sum),
max_sum(child, inc_sum, inc_sum - node.val))
return exc_sum, inc_sum
但我不确定在返回时交换exc_sum和inc_sum是否是实现结果的正确方法,以及如何跟踪可能导致最大总和的可能总和,在本例中,最大值左子树中的和是(1 + 3 + 4),而导致最终最大值的总和是(3 + 4 + 5),那么应该如何跟踪(3 + 4)?是否应将所有中间金额存储在表格中?
答案 0 :(得分:1)
让我们说 dp [u] [select] 存储答案:最大子序列总和,没有两个节点有边缘,因此我们只考虑以节点 u <为根的子树/ strong>(这样选择 u )。现在你可以编写一个递归程序,其中每个递归的状态为(u,select),其中 u 表示正在考虑的子图的根,选择表示我们是否选择节点 u 。所以我们得到以下伪代码
/* Initialize dp[][] to be -1 for all values (u,select) */
/* Select is 0 or 1 for false/true respectively */
int func(int node , int select )
{
if(dp[node][select] != -1)return dp[node][select];
int ans = 0,i;
// assuming value of node is same as node number
if(select)ans=node;
//edges[i] stores children of node i
for(i=0;i<edges[node].size();i++)
{
if(select)ans=ans+func(edges[node][i],1-select);
else ans=ans+max(func(edges[node][i],0),func(edges[node][i],1));
}
dp[node][select] = ans;
return ans;
}
// from main call, root is root of tree and answer is
// your final answer
answer = max(func(root,0),func(root,1));
除了递归之外,我们还使用了memoization来降低时间复杂度。它在空间和时间上都是 O(V + E)。你可以在这里看到一个工作版本
代码 Code 。单击右上角的叉子以在测试用例上运行
4 1
1 2
1 5
2 3
2 4
它按预期给出输出12。
输入格式在代码中的注释中指定,以及其他说明。它是用C ++编写的,但是一旦理解了代码,如果你想在python中使用它就没有重大的改变。如果您对代码有任何疑问,请在评论中发帖。