连接节点以最大化总边权重

Posted

技术标签:

【中文标题】连接节点以最大化总边权重【英文标题】:Connect nodes to maximize total edge weight 【发布时间】:2017-09-21 02:36:53 【问题描述】:

我正在研究一个可以简化为如下图优化问题的问题。

给出了一组彩色节点。它们都是未连接的,即图中没有边。

要在节点之间插入边。

一个节点最多只能有 4 条边。

表格提供了边缘利润贡献的规则。

例如,

连接红色和红色的边:利润为 10

连接红蓝的边:利润为 20

节点总数在100左右。

颜色总数通常在 20 到 30 种左右,但也可以高达 50 种。相应地,用于利润(边缘)的表格将是一个很长的列表,但它不会列出所有可能的组合。表中未指定边的利润假定为零。

问题是优化连接(边),使总利润最大化

我想知道这个问题是否已知,也许是其他方式。如果是这样,请提供任何可能有帮助的指示。谢谢。

【问题讨论】:

你的图是二分的吗? 最初只提供节点。他们都没有联系。图中没有边。 您能否发布一些示例输入,尤其是在幼稚的解决方案(首先创建最有利可图的连接,然后进行处理)不是最佳的情况下? 我建议将所有 k 个相同颜色的节点折叠成一个节点,现在允许有 4*k 个边,每个节点都可以用它所代表的颜色进行标记。 交叉发布:cs.stackexchange.com/q/74442/755、***.com/q/43587648/781723、***.com/q/43581690/781723。请do not post the same question on multiple sites。每个社区都应该诚实地回答问题,而不会浪费任何人的时间。 【参考方案1】:

这里是这个问题的线性规划公式:为“利润”表中存在的每个颜色对分配一个变量(最多需要 c*(c+1)/2 个变量,其中 c 是颜色的数量),使用c 由“每个节点 4 条边”限制和每个变量的一个约束来限制可能的边数的约束(除非每个边的颜色至少有 4 个节点或单色边有 5 个节点),并最大化可变*利润项的总和。

LP 求解器可能会为这个问题找到全整数变量(如果我们幸运的话)。或者可能存在带有小数变量的解决方案,请参见下面的反例。

当我们得到一个 LP 解决方案(其中每个变量代表某种颜色组合的边数)时,我们实际上应该在图中添加边。使用一些策略来避免循环和重复边(例如从相同颜色的节点中“选择连接最少的节点”)。


反例:5个红色,4个绿色,几个蓝色节点,红-绿边利润100,红-红10,红-蓝1。 LP 解给出 20 个红绿边缘(正确)、2.5 个红红边缘(应该是 2)和 0 个红蓝边缘(应该是 1)。

修复:整数线性规划是解决此问题的正确方法。对于多达 50 种颜色,我们需要多达 1275 个变量。对于一个体面的 ILP 求解器来说,这应该是相对简单的任务。

【讨论】:

【参考方案2】:

只是一个想法,没有太多时间验证它。 如何从加权图 G=(V,E) 开始,其中 V 是您的节点集,权重 E 是您的表的利润。令 O 为空集,作为我们的输出。

然后在 G 上使用匹配算法(Blossom 算法)。将这些边添加到 O。

使用输入 G'=(V,E\O) 重复该算法。再次将这些边添加到 O。

再重复两次。返回 O。

运行时间: 根据***,Blossom 算法的运行时间为 O(E*V^(1/2))。由于该算法使用了 4 次,因此总运行时间也是 O(E*V^(1/2))。

【讨论】:

【参考方案3】:

这听起来类似于 0-1 背包问题,如果将物品放入背包或未放入背包,则会计算最大值。这是一个例子:

def knapsack(numItems, capacity, sizes, values):
  # if no more items left to put in knapsack or knapsack is full
  if (numItems == 0 or capacity == 0):
    return 0

  # if can't fit item into knapsack, try the next item
  if (sizes[numItems-1] > capacity):
    knapsack(numItems-1, capacity, sizes, values)

  # find the max of including or not including item in knapsack
  return max(
    values[values-1] + knapsack(numItems-1,capacity - weights[numitems-1], sizes, values),
    knapsack(numItems-1, capacity, sizes, values))

在这里,当一个节点与另一个节点连接或不连接时,您正在寻找最大值。连接节点时,产生的值取决于节点的颜色。代码看起来像:

def ConnectNodes(numItems, capacity, sizes, values, nodeColor):
  # if no more items left to connect or capacity is full
  if (numItems == 0 or capacity == 0):
    return 0

  # if can't fit item into knapsack, try the next item
  if (sizes[numItems-1] > capacity):
    ConnectNodes(numItems-1, capacity, sizes, values, nodeColor)

  # find the max of connecting or not connecting node
  return max(
    RulesForProfit(numItems-1, nodeColor) + ConnectNodes(numItems-1,capacity - weights[numitems-1], sizes, values, nodeColor),
    ConnectNodes(numItems-1, capacity, sizes, values, nodeColor))

【讨论】:

【参考方案4】:

您是否考虑过贪婪的方法?对于所有颜色和相应的 colorA->colorB 值,如果对于每个有色边缘,您都会这样做

edge_color  :  sort_in_descending_order(edge_color_To_color_Prices)
example:
    red: red->black  30
         red->white  20
         red->yellow 10
    black: black->green 15
           black->grey 10

迭代直到有空间容纳新边缘(每个节点 4 个)和 取最大可能的边缘值(也将其标记为已访问,这将对您有所帮助)(我假设 您只能将 nodeA 与 nodeB 链接一次)。我们可以假设边缘是 不是根据你所说的。 在每个节点中,您必须存储这些选择的值,因此当您迭代已经使用的下一条边时,您必须注意选择的边(黑色节点必须知道红色->红色选择的黑色 30)

red: 1st edge: red->black 30 -> stores that in black node list as 
[red,30]
     2nd edge: ...........20 ->...
     3rd edge: ...........10
     4th edge: ...........5
     ---------------------------
     5th edge: ...........4   (after update from black it will be 4th 
edge)
black: 1st edge: black->white   50  > [red,30] 
       2nd edge: .............. 40
       3rd edge: .............. 35
       4th edge: .............. 34
       ---------------------------
       5th edge  .............. 30 (this is our red->black edge)

替换为 (black->white 50) 并转到红色节点以将其更新为下一个最大值(因为我们刚刚将 red->black 30 删除为 black->white 50 - 只有当我们达到遵循最小值标准的黑色节点中的边缘限制 - 我们正在从黑色节点中移除/替换价格最低的边缘)

应该可以的

【讨论】:

简单测试:4个红色节点,2个蓝色,2个绿色。红红 10,红蓝 7,红绿 6,绿绿 0,绿蓝 1,蓝蓝 0。答案是 26。 Simple test: 4 … Answer is 26 6*10+2*7+2*6+2*1?! 哦,抱歉,我忘记了 4 级。答案是 104。8*7+8*6 不是真的,不是我说的那种贪心,它是一个节点本地贪心算法,选择你现在可以选择的最好的,更新连接的节点,然后转到下一个节点。每次更新更新也是本地选择。所以它不是典型的贪心算法,它只是从贪心方法开始。 这个贪心算法没有给出最优解。不失一般性,我们将研究同样的问题,其中每个节点的边数限制为 1。假设有 4 个颜色为 a、b、c、d 的节点,利润值为 a,b=30 b,c=50 c,d=30。您的算法将只选择总利润为 50 的 b,c 边。而最佳解决方案是选择总利润为 60 的 a,b 边和 c,d 边。【参考方案5】:

您可以将其转换为寻找最大成本的完美匹配的问题,可以在多项式时间内解决(例如using a variant of the Blossom algorithm)

转换是将每个度数为d的节点拆分为d个左节点和d-4个右节点。

对于原图中的每一对顶点u,v,在一个未连接的顶点u左节点和一个未连接的顶点v左节点之间添加一条边,其权重等于加入u和v的收益。

接下来在每对左右节点(对于相同的顶点)之间添加额外的边(权重为 0)。

现在在这个新图中构建最大权重完美匹配。

关键是额外的边用完了除了 4 个左节点之外的所有节点。这意味着每个顶点只能从 4 个有利可图的边中获利。

示例

假设我们有 7 个彩色节点的问题。我已经绘制了对应于单个绿色节点和单个红色节点部分的展开图的部分。

请注意,左侧有 6 个绿色节点,比彩色节点的总数少 1 个。右侧有 2 个绿色节点,比左侧节点数少 4 个。有一条曲线连接绿色左节点和红色左节点。如果在完美匹配中选择了这条弯曲的边缘,则意味着红色节点应该连接到绿色节点。

【讨论】:

感谢您的宝贵时间。最初,图没有边,所有节点的度数为零。所以,我对此有点困惑:“将每个度数为 d 的节点分成 d 个左节点和 d-4 个右节点” 我正在考虑一个更一般的情况,即只允许一些边缘。在您的情况下,每个节点都可以连接到任何其他节点,因此如果您有 n 个顶点,则每个节点的有效度数为 n-1。因此,您需要将每个节点拆分为 n-1 个左节点和 n-5 个右节点。这将制作一个包含 O(n^2) 节点的相当大的中间图,所以我怀疑应该有比这个更有效的方法。 好的。知道了。感谢您的指点。我仍在阅读和理解匹配问题。 啊,我明白了。因此,拥有d 拆分节点的目的是每个拆分节点将连接到一个唯一的其他节点。好一个。整个算法的复杂度是多少? BlossomV 声称最坏情况复杂度 O(V^3E)。我们有 V=O(n^2) 和 E=O(n^3),所以总的来说这是最坏情况复杂度 O(n^9)!我认为这个答案主要用于表明问题不是 NP 难题——但我觉得必须找到更有效的解决方案。

以上是关于连接节点以最大化总边权重的主要内容,如果未能解决你的问题,请参考以下文章

使用 BFS/DFS 寻找有向无环图中权重最大的路径

找到最大权重的子图

有没有办法通过在一定范围内调整权重来最大化图的最大流量?

具有最大集群大小的集群

图最短路径?

带加权边缘的最大分布