1

这是一个类似问题的链接,有一个很好的答案:Java Algorithm for find the maximum set of independent nodes in a binary tree

我想出了一个不同的答案,但我的教授说它不起作用,我想知道为什么(他不回复电子邮件)。

问题:

给定一个包含 n 个整数的数组 A,它的索引从 0 开始(即 , A[0], A[1]..., A[n-1])。我们可以将 A 解释为一棵二叉树,其中的两个子节点A[i]A[2i+1]A[2i+2],每个元素的值就是树的节点权重。在这棵树中,如果一组顶点不包含任何父子对,我们就说它是“独立的”。独立集的权重只是其元素所有权重的总和。开发一种算法来计算任何独立集的最大权重。

我提出的答案使用了以下两个关于二叉树中独立集的假设:

  1. 同一级别的所有节点相互独立。
  2. 交替级别上的所有节点彼此独立(没有父/子关系)

警告:我在考试期间想出了这个,它并不漂亮,但我只是想看看我是否可以争取至少部分学分。

那么,为什么不能只构建两个独立的集合(一个用于奇数级别,一个用于偶数级别)?

如果每个集合中的任何权重都是非负的,则将它们相加(丢弃负元素,因为这不会对最大的权重集做出贡献)以找到具有最大权重的独立集。

如果集合中的权重都是负数(或等于 0),则对其进行排序并返回最接近 0 的负数作为权重。

比较两组中最大独立集的权重,并将其作为最终解决方案返回。

我的教授声称它不起作用,但我不明白为什么。为什么它不起作用?

4

2 回答 2

1

Interjay 已注意到您的答案不正确的原因。这个问题可以用递归算法来解决find-max-independent,给定一棵二叉树,考虑两种情况:

  1. 考虑到根节点包含在内,最大独立集是多少?
  2. 考虑到不包括根节点,最大独立集是多少?

在情况 1 中,由于包含了根节点,因此它的任何一个子节点都不能。因此,我们将find-max-independentroot 的孙子的值加上 root 的值(必须包括在内),然后返回。

在情况 2 中,我们返回子节点的最大值find-max-independent,如果有的话(我们只能选择一个)

该算法可能看起来像这样(在 python 中):

def find_max_independent ( A ):
    N=len(A)

    def children ( i ):
        for n in (2*i+1, 2*i+2):
            if n<N: yield n

    def gchildren ( i ):
        for child in children(i):
            for gchild in children(child):
                yield gchild

    memo=[None]*N

    def rec ( root ):
        "finds max independent set in subtree tree rooted at root. memoizes results"

        assert(root<N)

        if memo[root] != None:
            return memo[root]

        # option 'root not included': find the child with the max independent subset value
        without_root = sum(rec(child) for child in children(root))

        # option 'root included': possibly pick the root
        # and the sum of the max value for the grandchildren
        with_root =  max(0, A[root]) + sum(rec(gchild) for gchild in gchildren(root))

        val=max(with_root, without_root)
        assert(val>=0)
        memo[root]=val

        return val


    return rec(0) if N>0 else 0

一些测试用例说明:

tests=[
    [[1,2,3,4,5,6], 16], #1
    [[-100,2,3,4,5,6], 6], #2
    [[1,200,3,4,5,6], 200], #3
    [[1,2,3,-4,5,-6], 6], #4
    [[], 0],
    [[-1], 0],
]

for A, expected in tests:
    actual=find_max_independent(A)
    print("test: {}, expected: {}, actual: {} ({})".format(A, expected, actual, expected==actual))

样本输出:

test: [1, 2, 3, 4, 5, 6], expected: 16, actual: 16 (True)
test: [-100, 2, 3, 4, 5, 6], expected: 15, actual: 15 (True)
test: [1, 200, 3, 4, 5, 6], expected: 206, actual: 206 (True)
test: [1, 2, 3, -4, 5, -6], expected: 8, actual: 8 (True)
test: [], expected: 0, actual: 0 (True)
test: [-1], expected: 0, actual: 0 (True)

测试用例 1

测试用例 1

测试用例 2

测试用例 2

测试用例 3

测试用例 3

测试用例 4

测试用例 4

记忆算法的复杂度是O(n),因为rec(n)每个节点调用一次。这是一个使用深度优先搜索的自上而下的动态规划解决方案。

(测试用例插图由 leetcode 的交互式二叉树编辑器提供)

于 2014-06-07T19:12:06.847 回答
0

您的算法不起作用,因为它返回的节点集要么全部来自奇数级别,要么全部来自偶数级别。但是最佳解决方案可以同时具有来自两者的节点。

例如,考虑一棵树,除了两个权重为 1 的节点外,所有权重均为 0。其中一个节点位于级别 1,另一个位于级别 4。最佳解决方案将包含这两个节点且权重为 2。但是您的算法只会给出这些节点之一并且权重为 1。

于 2012-05-07T17:34:29.977 回答