简体   繁体   English

在有向无环图中,找到一条路径的权重是组成该路径的有向边的权重之和

[英]In Directed Acyclic graph, find the weight of a path is the sum of the weights of the directed edges comprising the path

You are given a directed acyclic graph G = (V,E). 您将得到有向无环图G =(V,E)。 Each directed edge e ∈ E has weight w_e associated with it. 每个有向边e∈E具有与之相关的权重w_e。 Given two vertices s,t ∈ V such that s has no incoming edge and t has no outgoing edge, we are interested in a maximum weight directed path that begins at s and ends at t. 给定两个顶点s,t∈V,使得s没有输入边,t没有输出边,我们对最大权重定向的路径感兴趣,该路径始于s,结束于t。 The weight of a path is the sum of the weights of the directed edges comprising the path. 路径的权重是构成路径的有向边的权重之和。 (A directed graph is acyclic if it has no directed cycles in it.) (如果有向图中没有有向环,则它是无环的。)

How do I solve it by using dynamic programming techniques? 如何使用动态编程技术解决它? I have been stuck for a while, any tips is appreciated:D 我已经被卡住了一段时间,任何提示都值得赞赏:D

The key here is an understanding that "dynamic programming" just means that for some function f(x), any repeated executions of f for some distinct input x results in either a different result or execution path. 这里的关键是要理解“动态编程”仅意味着对于某些函数f(x),对于某些不同的输入x重复执行f会导致结果或执行路径不同。 From this definition we can consider caching to be an instance of dynamic programming. 根据此定义,我们可以将缓存视为动态编程的一个实例。

So let's start with an implementation without dynamic programming. 因此,让我们从没有动态编程的实现开始。 Using backtracking, we can perform a DEPTH FIRST (this will be important later) set of traversals starting from s and ending at t . 使用回溯,我们可以执行从st的深度优先遍历(这将在以后变得很重要)。

let P(a,b) be a path from a->b
let w(p) be the total weight of some path p
let K be the exhaustive set of P(s,t) // a.k.a every path that exists

// Returns Max(p) p  ∈ K
function findMaxPath(G)
    return findMaxPath(s)

// Returns Max(P(n, t))
function findMaxPath(n)
   if (n === t)
      return an empty path // we are already at the target
   declare p = null
   for each e of n // every outgoing edge
     let q = G(n, e)
     let l = findMaxPath(q) // get the maximum path from the neighbor indice to t
     if (l == null) continue
     l = e + l // prepend the outgoing end to the max path of the child node
     if (w(l) > w(p)) p = l // this is most expensive outgoing end that eventually reaches t
   return p // return null if we can't reach t

The problem with this solution is that it is really slow. 该解决方案的问题在于它确实很慢。 In particular, you end up recalculating a LOT of paths. 特别是,您最终需要重新计算很多路径。 Take the following graph: 拍下图:

在此处输入图片说明

In the process of calculating the path from P(s, t), you end up executing findMaxPath(n) the following times for each n 在根据P(s,t)计算路径的过程中,最终对于每个n执行以下遍历findMaxPath(n)

  • findMaxPath(s) 1 findMaxPath(s)1
  • findMaxPath(a) 1 findMaxPath(a)1
  • findMaxPath(b) 1 findMaxPath(b)1
  • findMaxPath(c) 1 findMaxPath(c)1
  • findMaxPath(d) 3 findMaxPath(d)3
  • findMaxPath(e) 3 findMaxPath(e)3
  • findMaxPath(f) 3 findMaxPath(f)3
  • findMaxPath(g) 3 findMaxPath(g)3
  • findMaxPath(h) 9 (wow!) findMaxPath(h)9(哇!)

In this example findMaxPath(h) has to get calculated 9 times, a number that can increase dramatically in more complex topologies (this one is fairly trivial). 在此示例中,必须计算findMaxPath(h)9次,此数字在更复杂的拓扑中可能会急剧增加(这个数字相当微不足道)。 So to increase execution time, we can keep track of a "cache" of calls to findMaxPath(n). 因此,为了增加执行时间,我们可以跟踪对findMaxPath(n)的调用的“缓存”。 This is "dynamic" because the execution path of a function changes over time with identical variable inputs. 这是“动态的”,因为使用相同的变量输入,函数的执行路径会随时间变化。

let P(a,b) be a path from a->b
let w(p) be the total weight of some path p
let K(n) be the exhaustive set of P(n,t) // a.k.a every path that exists
let C be a cache of Max(w(p)) p ∈ K(n)
// Returns Max(w(p)) p ∈ K(s)
function findMaxPath(G)
    return findMaxPath(s)

// Returns Max(P(n, t))
function findMaxPath(n)
   if exists C[n]
     return C[n] // we already know the most expensive path from n->t
   if (n === t)
      return an empty path // we are already at the target
   declare p = null
   for each e of n // every outgoing edge
     let q = G(n, e)
     let l = findMaxPath(q) // get the maximum path from the neighbor indice to t
     if (l == null) continue
     l = e + l // prepend the outgoing end to the max path of the child node
     if (w(l) > w(p)) p = l // this is most expensive outgoing end that eventually reaches t
   C[n] = p
   return p // return null if we can't reach t

This gives us a total cache "hit" of 16/25 making the runtime substantially faster 这使我们的总缓存“命中”率为16/25,从而使运行时间大大加快

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM