【问题标题】:Find cycle of shortest length in a directed graph with positive weights在具有正权重的有向图中找到最短长度的循环
【发布时间】:2010-10-12 04:10:49
【问题描述】:

我在一次采访中被问到这个问题,但我想不出任何合适的解决方案。所以,我告诉他们找到所有周期然后选择长度最短的周期的幼稚方法。

我很想知道什么是解决这个问题的有效方法。

【问题讨论】:

    标签: algorithm graph dijkstra


    【解决方案1】:

    您可以轻松修改Floyd-Warshall algorithm。 (如果您根本不熟悉图论,我建议您检查一下,例如获取Introduction to Algorithms 的副本)。

    传统上,您为每个i 启动path[i][i] = 0。但您可以改为从path[i][i] = INFINITY 开始。它不会影响算法本身,因为无论如何这些零都没有用于计算(因为路径path[i][j] 永远不会改变k == ik == j)。

    最后,path[i][i] 是经过i 的最短循环的长度。因此,您需要为所有i 找到min(path[i][i])。如果你想要循环本身(不仅仅是它的长度),你可以像通常使用普通路径一样做:通过在算法执行期间记住k

    此外,您还可以使用Dijkstra's algorithm 找到通过任何给定节点的最短循环。如果您为每个节点运行此修改后的 Dijkstra,您将获得与 Floyd-Warshall 相同的结果。由于每个 Dijkstra 都是 O(n^2),因此您将获得相同的 O(n^3) 整体复杂度。

    【讨论】:

    • 这不符合要求。在这些算法中,最短意味着权重最小,而不是长度最短。例如如果有两个周期,例如 1,2,3,然后是 100,500;然后将选择循环 1,但需要的是循环 2,因为它的长度最短。如果我错了,请纠正我。
    • @Manoj 第二个问题是第一个问题的子集。只需为每条边分配权重 1,您将收到边数最少的路径。真正的问题(虽然很小)是 Dijkstra 和 Floyd-Warshal 都没有找到从节点返回到自身的最短路径。你必须稍微调整一下。
    • 谢谢..我使用了 Dijkstra 的修改版本,它工作了
    • 我认为您可以在 O(n^2) 次内完成此操作。使用 2 次 dijkstra 运行,两个嵌套的 for 循环将执行此操作。
    • 你能不能让这个工作也适用于无向图?
    【解决方案2】:

    伪代码是对 Dijkstra 算法的简单修改。

    for all u in V:
       for all v in V:
          path[u][v] = infinity
    
    for all s in V:
       path[s][s] = 0
       H = makequeue (V) .. using pathvalues in path[s] array as keys
       while H is not empty:
          u = deletemin(H)
          for all edges (u,v) in E:
             if path[s][v] > path[s][u] + l(u, v) or path[s][s] == 0:
                path[s][v] = path[s][u] + l(u,v)
             decreaseKey(H, v)
    
    lengthMinCycle = INT_MAX
    
    for all v in V:
       if path[v][v] < lengthMinCycle & path[v][v] != 0 :
          lengthMinCycle = path[v][v]
    
    if lengthMinCycle == INT_MAX:
       print(“The graph is acyclic.”)
    
    else:
       print(“Length of minimum cycle is ”, lengthMinCycle)
    

    时间复杂度:O(|V|^3)

    【讨论】:

    • 你首先将 path[s][s] 设置为 0,然后如果你有 ... 或 path[s][s] == 0,所以不断改变,即使它更长???错字?
    【解决方案3】:
    • 执行 DFS
    • 在 DFS 期间跟踪边缘的类型
    • 边缘类型为Tree EdgeBack EdgeDown EdgeParent Edge
    • 当您收到 Back Edge 并有另一个计数器用于获取长度时进行跟踪。

    详情请见Algorithms in C++ Part5 - Robert Sedgwick

    【讨论】:

    • 不错的尝试,但这充其量是指数级的复杂性。我怀疑,Robert Sedgwick 在他的书中解决了一些更普遍和复杂的问题,因为这个问题要容易得多。
    【解决方案4】:

    您要做的是为每个节点分配另一个权重,该权重始终为 1。现在使用这些权重运行从一个节点到同一节点的任何最短路径算法。但是在考虑中间路径时,您将不得不忽略实际权重为负的路径。

    【讨论】:

      【解决方案5】:

      以下是对 Floyd - Warshell 算法的简单修改。

      V = 4
      INF = 999999
      
      

      def minimumCycleLength(图): dist = [[0]*V for i in range(V)] 对于范围内的 i (V): 对于范围(V)中的j: dist[i][j] = 图[i][j]; 对于范围(V)中的k: 对于范围内的 i (V): 对于范围(V)中的j: dist[i][j] = min(dist[i][j] ,dist[i][k]+ dist[k][j]) 长度 = INF 对于范围内的 i (V): 对于范围(V)中的j: 长度 = min(长度,dist[i][j]) 返回长度

      graph = [ [INF, 1, 1,INF], [INF, INF, 1,INF], [1, INF, INF, 1], [INF, INF, INF, 1] ] length = minimumCycleLength(graph) print length

      【讨论】:

        猜你喜欢
        • 2014-01-17
        • 2019-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-27
        相关资源
        最近更新 更多