[英]Efficient traversal of a directed acyclic graph
输入:
nd[0];
nd[1, 2];
nd[3, 4];
nd[0, 1];
nd[2, 3];
nd[0, 4];
nd[1, 3];
nd[0, 2];
nd[1, 4];
nd[3];
nd[1, 4];
结果树:
输出:
total_time = sum of all individual wait_time //without overlap
规则:
问题 1:如何将给定的输入代码转换为图形以便遍历? (伪代码或任何类型的指导可能会有所帮助)
问题二:如何根据上述规则实现成功遍历?
以前的努力:
我能够使用Topological sort以线性方式对节点进行排序,但我不确定如何实现这些特定目标。
我根据代码的直觉绘制了这张图。
边缘上的数字只是为了澄清导致依赖的数字。
我正在使用 python 3
我以前的代码似乎与这些问题没有任何意义,所以我没有包含它。
设a, b, c
三个节点,它们共同具有0
属性/依赖关系(到节点 0)。 如果a
在b
之前被发现, b
在c
之前被发现,则边应该是a->b
和b->c
。
为了解决上述规则,请考虑为每个发现的数字缓存。 如果节点包含0
,则将其缓存为cache[0]
。 稍后,如果其他节点b
包含0
,则必须从cache[0]
到b
一条边,并更新该缓存,以便包含0
后续节点从b
获得一条边。
foreach input as node
forall dependancy of node
if discovered[dependancy]
make_edge(discovered[dependancy], node)
fi
discovered[dependancy] = node // apply dependancy "transitivity"
现在要将图形构建为“层”,您可以从叶子(层0
)开始,这里仅[1,4],[0,2],[0,3]
。 然后取其输出边链接到任何叶子的节点,这里只有[1,4]
。 (因为[1,3]
在链接到[3]
是叶子的同时,也链接到[1,4]
不是。所以排除了)。 然后,您已经构建了第1
层。
在构建第 n 层时,您只能将具有 deps 的节点添加到第 0 层到 n-1 层
一种更紧凑的说法是对于一个节点,计算它的离心率(最长的路径(这里是叶子))。
要像您一样打印图形,请注意您可以通过偏心率绘制节点,这将显示依赖的“级别”(它们离叶子/末端有多远,请参阅下面代码中的plotByLayers
)。
我们不需要像上面那样去构建层的麻烦。
一个节点只有在它的所有祖先都结束时才能开始。
当我们制作图表时,祖先已经确定了。
递归是这样的
n.endAt = max(n.endAt for n in n.ancestors) + n.wait
初始化是针对根节点(没有依赖关系)以及我们可以保持等待时间的地方。
nroot.endAt = nroot.wait
关于 node.id 符号i)x,y
。 i 是在输入中读取的第 i 个节点。 (不知何故x,y
它的真实id。x x,y
只是帮助我们形象化的垃圾)。
const input = ` nd[0]; nd[1, 2]; nd[3, 4]; nd[0, 1]; nd[2, 3]; nd[0, 4]; nd[1, 3]; nd[0, 2]; nd[1, 4]; nd[3]; nd[1, 4];` function makeGraph(input) { const nodes = input.trim().split('\\n').map((x,i) => { const deps = x.match(/\\[(.+)\\]/)[1] return { id: i+')'+deps, v: deps.split(',').map(x => x.trim()) } }) const edges = {} const discovered = {} nodes.forEach((node, i) => { node.v.forEach(digit => { if (discovered[digit]) { // there is an edge edges[discovered[digit].id] = edges[discovered[digit].id] || [] edges[discovered[digit].id].push(node) } // apply transitivity a->b->c discovered[digit] = node }) }) return {nodes, edges} } function computeEccentricity(n, edges) { if (typeof(n.eccentricity) !== 'undefined') { return n.eccentricity } if (!edges[n.id]) {// a leaf has no outgoing edges n.eccentricity = 0 return 0 } const distances = Object.values(edges[n.id]).map(n => computeEccentricity(n, edges)) const min = Math.max(...distances) n.eccentricity = 1 + min return n.eccentricity } function plotByLayers(nodes) { const lvls = [] let m = 0; nodes.forEach(n => { const i = n.eccentricity lvls[i] = lvls[i] || [] lvls[i].push(n) m = i > m ? i: m }) for(let i = m; i >=0 ; --i) { console.log(lvls[i].map(x => x.id)) } return lvls } const { nodes, edges } = makeGraph(input) nodes.forEach(n => computeEccentricity(n, edges)) plotByLayers(nodes) // for any node, compute its ancestors. nodes.forEach((n, i) => { if (edges[n.id]) { edges[n.id].forEach(v => { v.ancestors = v.ancestors || [] v.ancestors.push(n) }) } n.wait = 2**i // say arbitrarily that i node waits 2^i some time }) function computeEndAt(node) { if (typeof(node.endAt) !== 'undefined') { return node.endAt } if (!node.ancestors) { node.endAt = 0 + node.wait return node.endAt } const maxEnd = Math.max(...node.ancestors.map(computeEndAt)) node.endAt = maxEnd + node.wait return node.endAt } nodes.forEach(computeEndAt) const longest = nodes.sort((a,b)=>b.endAt - a.endAt)[0] console.log('awaited: ', longest.endAt, longest.id)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.