我在名为“Far Vertices”的访谈街遇到了动态编程问题。
问题是:
您将获得一个具有N个顶点和N-1个边的树。你的任务是 尽可能少地标记,以便最大化 两个未标记顶点之间的距离小于或等于K.你 应该将此值写入输出。两个顶点之间的距离i 和j定义为您必须传入的最小边数 为了从顶点j到达顶点i。
我试图从树的每个节点做dfs,以便找到节点的最大连通子集,这样每对子集的距离都不超过K. 但是我无法定义状态和状态之间的转换。
有没有人可以帮助我?
感谢。
答案 0 :(得分:3)
该问题基本上包括找到直径<= k的最大子树,并从n减去其大小。您可以使用DP解决它。
一些有用的观察结果:
以节点v(T(v))为根的树的直径为:
由于我们关心最大化树的大小和树的边界直径,我们可以翻转上面的内容来建议每个子树的限制:
现在是棘手的一点。如果n有多个子节点,我们必须找到通过为每个子节点分配可用深度而产生的所有可能的树大小。所以说我们处于深度3,k = 7,我们还有4个深度可以玩。如果我们有三个孩子,我们可以将所有4个分配给1个孩子,3个分配给1个孩子,1个分配给2个孩子,2个分配给1个孩子,1个孩子分配给2个孩子和3个孩子等。我们必须小心谨慎,确保我们不要超过直径k。您可以使用本地DP执行此操作。
我们想要为每个节点计算的是maxSize(d),它给出了以该节点为根的树的最大尺寸,其深度为d深,直径<= k。如上所述(例如,对于一个孩子,v.maxSize(i)= c.maxSize(i-1)+ 1,v.maxSize(0)= 1),具有0和1个孩子的节点很容易计算出来。 。有2个或更多子节点的节点,你计算dp [i] [j],它给出了一个k直径绑定树的最大大小,使用最多j个孩子占用j深度。递归是dp [i] [j] = max(child(i).maxSize(m-1)+ dp [i-1] [min(j,k-m)],m从1到j.d [ i] [0] = 1.这就是说,尝试给第i个孩子1到j深度,并将剩余的可用深度给予前面的节点。“剩余的可用深度”是j的最小值,深度我们正在使用或者k-m,因为给予其余的深度i +深度不能超过k。将dp的最后一行的值传递给该节点的maxSize表。如果你使用a运行上面的深度限制的DFS,它将以正确的顺序计算所有必需的maxSize条目,节点v的答案是v.maxSize(k)。然后你对树中的每个节点执行一次,答案是最大的价值找到。
对于解释的混乱性质感到抱歉。我很难思考,难以描述。通过一些简单的例子可以使它更清晰。我没有计算复杂性,但是n很小,它在Scala中经历了.5到1s的所有测试用例。
答案 1 :(得分:2)
我可以注意到一些基本的东西(对其他人来说可能非常明显): 1.两个给定顶点之间只有一条路线可能。 2.最远的顶点是只有一个外边缘的顶点。
现在解决这个问题。
我将从只有一条边的顶点集开始并称之为EDGE []来计算EDGE []中顶点之间的距离。这将给你(EDGE [i],EDGE [j],距离)值对
对于EDGE中距离>&gt;的所有顶点对。 K,DO EDGE [i] .occur ++,EDGE [i] .distance = MAX(EDGE [i] .distance,distance) EDGE [j] .occur ++,EDGE [j] .distance = MAX(EDGE [j] .distance,distance)
在EDGE []中查找具有最大(距离)的候选人与最大(出现)标记的人
重复直到所有边缘顶点对的距离小于或等于K