假设我们有一个标有数字的边缘的DAG。将路径的值定义为标签的乘积。对于每个(源,接收器)对,我想找到从源到接收器的所有路径的值的总和。您可以使用动态编程在多项式时间内执行此操作,但仍然可以在如何分解问题时做出一些选择。在我的情况下,我有一个DAG必须使用不同的标签重复评估。我的问题是:对于给定的DAG,我们如何预先计算一个好的策略来重复计算不同标签的这些值?如果有一种算法可以找到最佳方式,那将是很好的,例如一种最小化乘法次数的方法。但也许这个问题太多了,我会对一个只能给出良好分解的算法感到非常满意。
答案 0 :(得分:1)
设S为源集合,V为DAG的顶点集合,E为边集合,n = | V |,m = | S |,W为存储边权重的nxn矩阵,并且C是m×n矩阵,使得C [i,j]在算法结束时保持从i到j的所有路径的值的总和。 为了简化算法的解释和正确性证明,我假设从1到n的图的顶点是拓扑排序的,其中节点1到m是源。这会将O(| E | + | V |)添加到算法的运行时间:
以下是算法的伪代码:
1: set C[i,j] to 1 if i=j and i is a source node, and to 0 otherwise.
2: sort the DAG topologically
3: for k=1 to n (vertex traversal in the topological order)
4: foreach predecessor k' of vertex k
5: foreach i in S
6: C[i,k] += C[i,k']*W[k',k]
两个外部循环总共有O(| E | + | V |)迭代。因此,算法的运行时间为O((| V | + | E |)。m),假设加法和乘法需要恒定的时间。这包括拓扑排序的时间。
正确性证明:我们通过归纳证明,在最外层循环的第k次迭代完成后,C [i,k]是从i到i的所有路径的值的总和s中每个i的k
基础案例:对于k = 1显而易见(因为第一个元素没有任何前辈)
归纳:假设对于所有j <1,正确计算C [i,j]。 ķ。从任何源i到k的所有路径必须通过k的前驱k'。由于我们以拓扑顺序迭代,因此k'必须小于k,并且根据我们的归纳假设C [i,k']是从i到k'的路径值的总和。此外,通过特定前驱k'的从i到k的路径的值的总和等于从i到k'的路径的值的总和,即,C [i,k'],乘以W [k ”,K]。因此,从i到k的所有路径的值的总和是在k的所有前驱k'上的C [i,k'] * W [k',k]的和。
相同的图形结构,不同的W矩阵:如果我们需要为具有相同结构但不同W的不同图形计算矩阵C,我们可以执行以下操作:设C'为矩阵元素是3元组的列表。用
替换上面的第6行C'[i,k].append((i,k',k))
然后通过迭代拓扑顺序中的顶点并迭代C'[i,k]中的元组,您可以在不查看图形结构的情况下计算C [i,k]。那是因为元组隐式表示图结构。就复杂性而言,这不是更好或更糟。