求n进制树中最大非邻接和的算法

时间:2015-03-05 07:03:30

标签: algorithm tree dynamic-programming maximize

给定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)?是否应将所有中间金额存储在表格中?

1 个答案:

答案 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中使用它就没有重大的改变。如果您对代码有任何疑问,请在评论中发帖。