将节点连接以最大化总边权值

23

我正在解决一个问题,它可以简化为以下的图优化问题。

  • 给定一组有颜色的节点。它们都没有连接,即在图中没有边。

  • 需要在这些节点之间插入边。

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

  • 一张表格提供了从边缘获得利润的规则。

    例如,

    • 将红色节点与红色节点连接的边缘:利润为10。

    • 将红色节点与蓝色节点连接的边缘:利润为20。

  • 总节点数约为100个。

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

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

我想知道是否已经有人研究过这个问题,如果有,请提供任何有帮助的参考。谢谢。


你的图是二分图吗? - Peter de Rivaz
最初,只提供节点。它们都未连接。图中没有边。 - Suresh
1
你能发布一些示例输入吗?特别是那些天真的解决方案不是最优的情况。 - m69 ''snarky and unwelcoming''
我建议将所有颜色相同的k个节点合并为一个节点,该节点现在可以拥有4*k条边,并且每个节点都可以标记其所代表的颜色。 - Beginner
1
跨站发布:https://cs.stackexchange.com/q/74442/755,https://dev59.com/F1cP5IYBdhLWcg3w8udi,http://stackoverflow.com/q/43581690/781723。请不要在多个网站上发布相同的问题。每个社区都应该有诚实的机会回答,而不浪费任何人的时间。 - D.W.
5个回答

14
你可以将这转化为寻找最大代价的完美匹配问题,该问题可以在多项式时间内解决(例如,使用Blossom算法的变体)。
转换是将每个度数为d的节点分成d个左节点和d-4个右节点。
对于原始图中的每对顶点u、v,在未连接的顶点u左节点和未连接的顶点v左节点之间添加一个权重等于加入u和v的利润的边。
接下来,在同一顶点的每对左节点和右节点之间添加额外的边(权重为0)。
现在在这个新图中构造最大权重的完美匹配。
关键在于额外的边使用所有除了4个左节点。这意味着每个顶点只能从4个有利可图的边中获得利润。
例子
假设我们有一个包含7个彩色节点的问题。我已经画出了对应于单个绿色节点和单个红色节点部分的扩展图。
请注意,左侧有6个绿色节点,比彩色节点的总数少一个。右侧有2个绿色节点,比左侧节点少4个。有一条弯曲的边连接着一个绿色左侧节点和一个红色左侧节点。如果在完美匹配中选择了这条弯曲的边,则意味着应将红色节点与绿色节点相连。

enter image description here


感谢您的时间。最初,图中没有边,所有节点的度数为零。因此,我对此有些困惑:“将每个度数为d的节点分成d个左节点和d-4个右节点”。 - Suresh
1
我在考虑一种更一般的情况,只允许某些边存在。在你的情况下,每个节点都可以连接到任何其他节点,因此如果你有n个顶点,则每个节点的有效度数为n-1。因此,您需要将每个节点分成n-1个左节点和n-5个右节点。这将产生一个相当大的中间图,具有O(n^2)个节点,因此我怀疑应该有比这更高效的方法。 - Peter de Rivaz
好的,明白了。感谢指点。我仍在阅读和理解匹配问题。 - Suresh
1
啊,我明白了。所以拥有d个分裂节点的目的是每个分裂节点将连接到唯一的其他节点。不错。整个算法的复杂度是多少? - justhalf
3
BlossomV声称最坏情况下的复杂度为O(V^3E)。我们有V=O(n^2)和E=O(n^3),因此总体而言,这是最坏情况下的复杂度为O(n^9)!我认为这个答案主要有助于表明问题不是NP难题 - 但我觉得一定有更有效率的解决方案可以找到。 - Peter de Rivaz
显示剩余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))

3
这里是针对这个问题的线性规划公式:为"profit"表中存在的每种颜色配对分配一个变量(需要最多c*(c+1)/2个变量,其中c是颜色数),使用c个由“每个节点4条边”限制确定的约束以及每个变量的一个约束来限制可能边的数量(除非每种颜色的边至少有4个节点或单色边至少有5个节点),并最大化变量*收益项的总和。
LP求解器可能会找到此问题的所有整数变量(如果我们很幸运的话)。或者可能会有带有分数变量的解决方案,请参见下面的反例。
当我们获得LP解(其中每个变量表示某种颜色组合的边数)时,我们实际上应该向图形添加边缘。使用一些策略避免循环和重复边(例如从相同颜色的节点中“选择最少连接的节点”)。
反例:5个红色,4个绿色,若干个蓝色节点,红-绿边的收益为100,红-红为10,红-蓝为1。LP解给出20个红-绿边(正确),2.5个红-红边(应为2),以及零个红-蓝边(应为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))。


2

您是否考虑过贪心算法?对于所有颜色及其相应的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)

替换成 (黑色->白色 50),然后转到红节点以使用下一个最大值更新它(因为我们刚刚通过黑色->白色 50 删除了红色->黑色 30 - 只有在按照最小值标准遵循黑色节点中的边数限制时才替换它 - 我们正在从黑色节点中移除/替换最低价格的边)

应该可以了


简单测试:4个红节点,2个蓝色,2个绿色。红-红10,红-蓝7,红-绿6,绿-绿0,绿-蓝1,蓝-蓝0。答案是26。 - DAle
简单测试:4 … 答案是26 610+27+26+21?! - greybeard
哦,抱歉,我忘记了4次方。答案是104。87+86。 - DAle
其实不是那种贪心,我说的是一种节点本地贪心算法,选择当前最佳选项,更新相邻节点,然后进入下一个节点。每次更新也会更新本地选择。因此,它不是典型的贪心算法,只是从贪心的角度开始。 - Tomasz Andel
610+47+4*1 = 92 (10,10,10,7)(10,10,10,7)(10,10,10,7)(10,10,10,7)(7,7,1,1)(7,7,1,1)(1,1)(1,1) 的意思是92。 - Tomasz Andel
1
这种贪心算法并不能给出最优解。为了不失一般性,我们将考虑限制每个节点的边数为1的相同问题。假设有4个带有颜色a、b、c、d的节点,并且利润值分别为{a,b}=30 {b,c}=50 {c,d}=30。你的算法只会选择具有总利润50的b,c边。然而最优解是选择a,b边和c,d边,总利润为60。 - Gastmon

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