寻找树中最大子集,使得该子集中任意两点之间的距离不超过K。

3
我在面试街上遇到了一个名为“Far Vertices”的动态规划问题。
问题如下:
给定一个有N个顶点和N-1条边的树。你的任务是尽可能标记少量的顶点,以使两个未标记的顶点之间的最大距离小于或等于K。您应该将此值写入输出。两个顶点i和j之间的距离定义为必须经过的最小边数,才能从顶点j到达顶点i。
我试图从树的每个节点开始进行深度优先搜索,以找到节点的最大连接子集,使得每对子集的距离都不超过K。但我无法定义状态和状态之间的转换。
是否有人能帮助我?
谢谢。

我认为你应该通过迭代修剪最少叶子节点的子树,从而将其降至O(N^2)。我会详细说明并稍后发布答案。 - beaker
抱歉,贪心算法对我来说不起作用。您需要找到每个子树的0..k个最低级别的最优组合,这将使复杂度大于Techmonk的答案。 - beaker
2个回答

3
问题本质上是找到直径<=k的最大子树,并从n中减去它的大小。可以使用DP解决。
一些有用的观察结果:
以节点v为根的树(T(v))的直径为:
1.如果n没有孩子,则为1, 2.如果有一个孩子c,则为max(diameter T(c), height T(c) + 1), 3.如果有多个孩子,为max(max(diameter T(c)) for all children c of v, max(height T(c1) + height T(c2) + 2) for all children c1, c2 of v, c1 != c2)
由于我们关心的是最大化树的大小并限制树的直径,因此我们可以将上述情况翻转,以表明每个子树的限制:
1.对于任何以v为根的树,感兴趣的子树最多只有k层。 2.如果n是T(v)中的一个节点,并且距离v不超过k,其最大大小为1。 3.如果n有一个孩子c,则直径<=k的T(n)的最大大小为max size T(c) + 1。
现在是棘手的部分。如果n有多个孩子,我们必须找到分配可用深度给每个孩子所导致的所有可能的树大小。因此,假设我们在深度3,k = 7,我们还有4个深度可以使用。如果我们有三个孩子,我们可以将所有4个分配给第一个孩子,将3个分配给第一个孩子和1个分配给第二个孩子,将2个分配给第一个孩子,1个分配给孩子2和3等。我们必须小心地做这件事,确保不超过直径k。您可以使用本地DP来完成此操作。
我们希望对每个节点计算maxSize(d),这给出了以该节点为根的树的最大大小,该树在深度为d时具有直径<=k。对于0和1个子节点的节点,很容易弄清楚这一点(例如,对于一个子节点,v.maxSize(i) = c.maxSize(i - 1) + 1,v.maxSize(0)=1)。对于有2个或更多子节点的节点,您需要计算dp[i][j],它给出了使用最多i个子节点,深度最多为j的k-直径限制树的最大大小。递归是dp[i][j]= max(child(i).maxSize(m-1)+ dp[i-1][min(j,k-m)] for m from 1 to j. d[i][0]=1。这意味着,尝试为第i个子节点提供1到j的深度,并将其余可用深度分配给先前的节点。剩余的可用深度是j、我们正在处理的深度或k-m的最小值,因为分配给子节点i+分配给剩余部分的深度不能超过k。将dp的最后一行的值传输到此节点的maxSize表中。如果使用深度受限的DFS运行上述代码,则会按正确顺序计算所有必需的maxSize条目,节点v的答案是v.maxSize(k)。然后,您需要为树中的每个节点执行此操作一次,答案是找到的最大值。 对于说明的混乱,我很抱歉。对我来说很难思考,也很难描述。通过几个简单的示例,应该会更清楚。我没有计算复杂度,但n很小,在Scala中经过了所有测试用例,需要0.5到1秒。

当你说 dp[i][0] = 1 时,这是针对当前根节点,对吗? - Pavel Podlipensky

2

有几个基本的事情我能够注意到(对于其他人可能非常明显): 1. 两个给定顶点之间只有一条路线可行。 2. 最远的顶点将是仅具有一个出边的顶点。

现在来解决这个问题。

  1. 我会从仅有一条边的顶点集开始,并称它们为EDGE[],计算EDGE[]中顶点之间的距离。这将给你(EDGE[i], EDGE[j], distance)值对。

  2. 对于EDGE中所有距离大于K的顶点对,执行EDGE[i].occur ++,EDGE[i].distance = MAX(EDGE[i].distance, distance) EDGE[j].occur ++,EDGE[j].distance = MAX(EDGE[j].distance, distance)

  3. 在EDGE[]中找到具有最大距离的CANDIDATES,标记它们的最大(occur)

  4. 重复步骤3,直到所有边缘顶点对的距离小于或等于K


我认为你的算法应该能够计算出正确的结果。 但是时间复杂度是指数级的,不可接受。 应该有一些动态规划算法来解决这个问题。 - Rowen
这将是O(n^3)。不算指数级别的。我认为,如果找到距离的实现足够好,甚至可以达到O(n^2*log(n))。 - Techmonk
如果这有助于你的复杂度,您可以在O(N ^ 2)时间内找到所有对最短路径(或者更确切地说,所有对唯一路径)。 - beaker
抱歉,我尝试了这个算法,并发现了一个你的算法无法处理的情况。这个情况是n=12,k=3,边为(1 3)/(2 3)/(3 4)/(4 5)/(4 6)/(6 7)/(7 8)/(8 9)/(9 10)/(10 11)/(10 12)。在这种情况下,算法返回了7,实际上结果应该是6。 - Rowen
第一次迭代会给你返回(1,11) (1,12) (2,11) (2,12) (5,11) (5,12),在这种情况下,由于11和12出现的次数最多,你必须删除其中一个,最终按照逻辑,你将得到6作为答案。 - Techmonk
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接