具有负权重的最小产品生成树
Minimum product spanning tree with negative weights
假设如果所有边的权重都是正数,则可以通过对每条边取log
得到最小乘积生成树,然后应用Kruskal或Prim。但是如果一些权重是负的,我们就不能应用这个过程。因为我们需要包括奇数个负边,并且这些边必须具有最大权重。遇到这种情况怎么办?
这是一个简单的解决方案。如果至少有一条负边,找到最大化 log(abs(edge)) 总和的最优生成树。然后,检查实际产品(没有 abs)是否为负数。如果负输出当前生成树,否则用负边替换其中一个正边或用正边替换负边以获得解决方案。
如果 none 条边为负数,最小化 log(edge) 总和应该可行。
复杂度:O(n^2),采用简单的解决方案。
关于朴素算法的更多解释:
Select 具有最低移除绝对值的边缘。删除这条边会将树分成两部分。我们可以遍历边缘值最大的那些集合之间的每一对(根据情况应该是正数或负数)。这部分的复杂度是 O(n^2).
我们可能必须尝试移除多条边才能获得最佳解决方案。假设我们遍历每条边,复杂度为 O(n^3).
我非常有信心这可以改进。
我非常怀疑您是否可以修改 Prims 算法来解决这个问题,因为负数会完全改变它。如果您设法获得负结果,则必须最大化绝对值,这意味着必须使用具有最高绝对值的边缘,因此尝试优化 Prims 算法找到的结果并采用 log(abs()) 将行不通,除非不可能得到否定的结果,否则这实际上是 return 最好的解决方案。
这让问题变得更简单了,因为我们只需要寻找最好的负解,如果我们没有找到任何我们使用 Prims with log(abs())。
如果我们为每个顶点分配一个值 1,则可以通过创建一个新顶点来合并两个顶点,该新顶点具有两个顶点的所有边(连接它们的边除外),并且该值是删除的值的乘积顶点和边。
基于此我们可以开始简化,将所有节点合并为一条边。与每个合并步骤并行,删除的边必须标记为在原始图中使用,以便最终可以从标记的边重建树。
此外,我们可以合并所有只有正边或只有负边的节点,删除绝对值最高的边。合并后,新节点可以与同一节点有多个连接,您可以丢弃除具有最高绝对值的负边缘和正边缘之外的所有连接(因此最多 2 个边缘到同一节点)。顺便提一句。一旦我们有到同一个节点的 2 条边(遵循上面的删除条件),我们就知道必须存在 <= 0 的解决方案。
如果你最终得到一个节点并且它是负的那么问题就成功解决了,如果它是正的则没有负的解决方案。如果我们有一个 0 顶点,我们可以按任何顺序合并其余节点。更有可能的是,我们最终得到一个高度连接的图,其中每个节点至少有一个负边和一个正边。如果我们有奇数个负顶点,那么我们想合并具有偶数个负边的节点,反之亦然。
总是按绝对值最大的边合并。如果生成的顶点 <= 0 那么您找到了最佳解决方案。否则会变得复杂。您可以查看所有未使用的边,尝试添加它,看看可以删除哪些边以使其再次成为树,只查看具有不同符号的边并构建比率 abs(added_edge/removed_edge)。然后最后以最佳比例进行更改(如果找到任何符号相反的组合,否则没有负解)。但我不是 100% 确定这是否总能给出最好的结果。
假设如果所有边的权重都是正数,则可以通过对每条边取log
得到最小乘积生成树,然后应用Kruskal或Prim。但是如果一些权重是负的,我们就不能应用这个过程。因为我们需要包括奇数个负边,并且这些边必须具有最大权重。遇到这种情况怎么办?
这是一个简单的解决方案。如果至少有一条负边,找到最大化 log(abs(edge)) 总和的最优生成树。然后,检查实际产品(没有 abs)是否为负数。如果负输出当前生成树,否则用负边替换其中一个正边或用正边替换负边以获得解决方案。
如果 none 条边为负数,最小化 log(edge) 总和应该可行。
复杂度:O(n^2),采用简单的解决方案。
关于朴素算法的更多解释: Select 具有最低移除绝对值的边缘。删除这条边会将树分成两部分。我们可以遍历边缘值最大的那些集合之间的每一对(根据情况应该是正数或负数)。这部分的复杂度是 O(n^2).
我们可能必须尝试移除多条边才能获得最佳解决方案。假设我们遍历每条边,复杂度为 O(n^3).
我非常有信心这可以改进。
我非常怀疑您是否可以修改 Prims 算法来解决这个问题,因为负数会完全改变它。如果您设法获得负结果,则必须最大化绝对值,这意味着必须使用具有最高绝对值的边缘,因此尝试优化 Prims 算法找到的结果并采用 log(abs()) 将行不通,除非不可能得到否定的结果,否则这实际上是 return 最好的解决方案。
这让问题变得更简单了,因为我们只需要寻找最好的负解,如果我们没有找到任何我们使用 Prims with log(abs())。
如果我们为每个顶点分配一个值 1,则可以通过创建一个新顶点来合并两个顶点,该新顶点具有两个顶点的所有边(连接它们的边除外),并且该值是删除的值的乘积顶点和边。
基于此我们可以开始简化,将所有节点合并为一条边。与每个合并步骤并行,删除的边必须标记为在原始图中使用,以便最终可以从标记的边重建树。
此外,我们可以合并所有只有正边或只有负边的节点,删除绝对值最高的边。合并后,新节点可以与同一节点有多个连接,您可以丢弃除具有最高绝对值的负边缘和正边缘之外的所有连接(因此最多 2 个边缘到同一节点)。顺便提一句。一旦我们有到同一个节点的 2 条边(遵循上面的删除条件),我们就知道必须存在 <= 0 的解决方案。
如果你最终得到一个节点并且它是负的那么问题就成功解决了,如果它是正的则没有负的解决方案。如果我们有一个 0 顶点,我们可以按任何顺序合并其余节点。更有可能的是,我们最终得到一个高度连接的图,其中每个节点至少有一个负边和一个正边。如果我们有奇数个负顶点,那么我们想合并具有偶数个负边的节点,反之亦然。
总是按绝对值最大的边合并。如果生成的顶点 <= 0 那么您找到了最佳解决方案。否则会变得复杂。您可以查看所有未使用的边,尝试添加它,看看可以删除哪些边以使其再次成为树,只查看具有不同符号的边并构建比率 abs(added_edge/removed_edge)。然后最后以最佳比例进行更改(如果找到任何符号相反的组合,否则没有负解)。但我不是 100% 确定这是否总能给出最好的结果。