如何找到最小化边数的方法?
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 的权重。
【讨论】:
以上是关于如何找到最小化边数的方法?的主要内容,如果未能解决你的问题,请参考以下文章