如何找到最小化边数的方法?

Posted

技术标签:

【中文标题】如何找到最小化边数的方法?【英文标题】:How can I find a way to minimum the number of edges? 【发布时间】:2014-11-12 09:29:34 【问题描述】:

我正在考虑一种算法来解决以下问题:

由顶点和边组成的给定图。

有 N 个客户想要从一个顶点旅行到另一个顶点。 并且每个客户需求都需要一条有向边来连接两个顶点。

问题是如何找到满足所有客户要求的最小边数?

有一个简单的例子:

客户 1 想从顶点 a 移动到顶点 b。 客户 2 想从顶点 b 移动到顶点 c。 客户 3 想要从顶点 a 移动到顶点 c。

最简单的方法是为每个客户提供优势:

边 1:顶点 a -> 顶点 b 边 2:顶点 b -> 顶点 c 边 3:顶点 a -> 顶点 c

但实际上只需要 2 条边(即边 1 和边 2)即可满足三个客户要求。

如果客户数量很大,如何找到满足所有客户需求的最小边?

有解决这个问题的算法吗?

【问题讨论】:

是的,图中的每条边都是有向边!那是我的错,我应该强调给定的图是有向图。 这是传递约简的问题。 en.wikipedia.org/wiki/Transitive_reduction 我很确定您的意思是“每个客户要求都需要一个有向的路径来连接两个顶点。”如果您真的是指“有向边”,那么问题很简单,您的示例问题的答案需要所有 3 条边。 其实我只是想尽量减少边的数量并确保可达性不变。 传递约简可能不是答案。如果我们有 a->b、a->c、b->d、c->d 之类的客户需求,那么传递约简保留所有客户弧,而三个弧 a->b、b->c、c ->d 产生尽可能多的连接。如果我们只能构建某个客户要求的弧,那么我们不需要传递约简,而是需要最小等价子图(NP-hard to find if there are cycles)。 【参考方案1】:

您可以将问题建模为混合整数程序。您可以为“arc a-> b is used”和“customer c uses arc a -> b”定义二进制变量,并将要求写为线性不等式。如果您的图不是太大,您可以通过混合整数程序求解器(CPLEX、GUROBI,但网络上也有免费的替代方案)在合理的时间内求解此类模型。

我知道如果您不熟悉线性规划,这个解决方案需要一些工作,但它保证在有限的时间内找到最佳解决方案,并且您可能可以为(比如说)1000 个客户和 1000 个弧线解决它。

【讨论】:

【参考方案2】:

如果你有 N 个顶点,你总是可以用 N 个(有向)边构造一个解。只需创建一个有向循环 V_1 -> V_2 -> V_3 ->... -> V_N -> V_1。您永远不可能有从每个顶点 V_a 到具有较少边的每个其他顶点 V_b 的有向路径(因为您将拥有一个必然包含叶子的有向树)。叶子要么不可到达(如果边缘从叶子向外),或者叶子是接收器(不能连接到其他任何东西)如果边缘是 ->叶子。

【讨论】:

【参考方案3】:

无需使用任何新算法。您可以使用 BFS/DFS 算法。

Find if there exists any path between source and destination.
   if !true
      add a direct edge between source and destination
      count++;
return count; 

这里的关键部分不是循环遍历图形,而是循环遍历新添加的边。

【讨论】:

【参考方案4】:

您可以使用不相交集数据结构。

https://en.wikipedia.org/wiki/Disjoint-set_data_structure

while (num_edges--)
    if root(vertex_a) != root(vertex_b)
    count++
    union(vertex_a,vertex_B)

【讨论】:

【参考方案5】:

如果我想到无向边的同样问题,我们正在寻找的是原始图(由所有边构成)的minimum spanning tree (MST)。简单的解释是,对于每条边 E (v1 -> v2),如果有第二条从 v1 到 v2 的路径,则存在一个环,并且对于每个现有的环,我们可以省略一条边。

要查找有向图的 MST,您可以使用 Chu–Liu/Edmonds' algorithm。

请注意,您为所有边分配了 1 的权重。

【讨论】:

以上是关于如何找到最小化边数的方法?的主要内容,如果未能解决你的问题,请参考以下文章

求两个数的最小公倍数

ZOJ 3792 Romantic Value 最小割(最小费用下最小边数)

Kruskal 找到最小生成树

C++求两个数的最小公倍数—枚举法

P4208 [JSOI2008]最小生成树计数

P4208 [JSOI2008]最小生成树计数