(注意:我考虑在https://cstheory.stackexchange.com/上问这个问题,但我认为我的问题不够理论 - 它是关于算法的。如果有一个更好的Stack Exchange社区发帖,我很高兴听!)
我使用术语"起始节点"表示没有链接的节点,"终端节点"表示没有链接的节点。因此下图包含起始节点A和B以及终端节点F和G:
我想用以下规则绘制它:
使用这些规则,上图显示了每个节点的深度。有人可以建议一种算法来计算在不到O(n ^ 2)的时间内运行的每个节点的深度吗?
我调整了图表以显示DAG可能包含不同深度的起始节点和终端节点。 (这是我在原来的错误答案中没有考虑过的情况。)我还从" x坐标"中切换了术语。到"深度"为了强调这是关于"图表"而不是"图形"。
答案 0 :(得分:0)
节点的x
坐标对应于从任何节点开始的最长路径,而不会在此问题上出现边缘。对于DAG,可以在O(N)
:
given DAG G:
calculate incomming_degree[v] for every v in G
initialize queue q={v with incomming_degree[v]==0}, x[v]=0 for every v in q
while(q not empty):
v=q.pop() #retreive and delete first element
for(w in neighbors of v):
incomming_degree[w]--
if(incomming_degree[w]==0): #no further way to w exists, evaluate
q.offer(w)
x[w]=x[v]+1
x
存储所需信息。
答案 1 :(得分:0)
这是一个基本上是两遍深度优先树步行的解决方案。第一遍(traverseA)跟踪起始节点(在O.P。的示例中为A和B)的DAG,直到遇到终端节点(示例中为F和G)。它们用图中描绘的最大深度标记它们。
第二遍(traverseB)从终端节点开始并追溯到起始节点,沿着节点的当前值或前一节点的值减一,标记每个节点,以较小者为准如果尚未访问该节点,则该值更小:
function labelDAG() {
nodes.forEach(function(node) { node.depth = -1; }); // initialize
// find and mark terminal nodes
startingNodes().forEach(function(node) { traverseA(node, 0); });
// walk backwards from the terminal nodes
terminalNodes().forEach(function(node) { traverseB(node); });
dumpGraph();
};
function traverseA(node, depth) {
var targets = targetsOf(node);
if (targets.length === 0) {
// we're at a leaf (terminal) node -- set depth
node.depth = Math.max(node.depth, depth);
} else {
// traverse each subtree with depth = depth+1
targets.forEach(function(target) {
traverseA(target, depth+1);
});
};
};
// walk backwards from a terminal node, setting each source node's depth value
// along the way.
function traverseB(node) {
sourcesOf(node).forEach(function(source) {
if ((source.depth === -1) || (source.depth > node.x - 1)) {
// source has not yet been visited, or we found a longer path
// between terminal node and source node.
source.depth = node.depth - 1;
}
traverseB(source);
});
};