让我们考虑以下问题:对于有向非循环图G = (V,E)
,我们为每个顶点u定义函数“levels”,如l(u)
所示:
1。 l(u)> =每个u的0
2。如果有从u到v(u - > v)的路径,则l(u)> l(v)
3. 对于每个顶点u,l(u)是满足条件1和2的最小整数。
问题是:
a。证明对于每个DAG,上述功能是唯一定义的,即它是唯一满足条件1,2和3的功能。
b。查找为每个顶点计算此函数的O(|V| + |E|)
算法。
以下是基于拓扑排序的可能算法:
首先,我们找到G的转置,G^T
,定义为G^T = (V,E^T)
,其中E^T={(u,v): (v,u) is in E}
如果基于邻接列表实现,总共取O(|V|+|E|)
:
(O(|V|)
用于分配和sum for all v in V of |Adj[v]| = O(|E|))
。拓扑排序需要Theta(|V|+|E|)
,因为它在列表中包含BFS和|V|
插入,每个插入O(1)
。
TRANSPOSE(G){
Allocate |V| list pointers for G^T i.e. (Adj'[])
for(i = 1, i <= |V|, i++){
for every vertex v in Adj[i]{
add vertex i to Adj'[v]
}
}
}
L = TopSort(G)
答案 0 :(得分:2)
一个。证明对于每个DAG,上述函数是唯一定义的,即它是满足条件1,2和3的唯一函数。
也许我错过了一些东西,但这对我来说似乎很明显:如果你把它定义为满足这些条件的最小值,那么怎么会有不止一个?
湾找到一个为每个顶点计算此函数的O(| V | + | E |)算法。
我认为你的拓扑排序是正确的(注意拓扑排序 是BFS),但它应该在转置图上执行(反转每个边的方向)。然后拓扑排序中的第一个值得到0,下一个得到1等。例如,对于转置图:
1 2 3
*-->*-->*
^
*-------|
1
我已经在拓扑排序中对节点进行了编号。您可以通过使用BFS实现拓扑排序来对节点进行编号。从FIFO队列中提取节点时,从所有可到达节点的indegree中减去1。当该indegree变为0时,在队列中插入它变为0的节点,并将其编号为exracted_node + 1.在我的示例中,编号为1的节点以indegree 0开头。然后,最底部的1从indegree中减去1标记为3的节点,但该indegree将为1,而不是零,因此我们不会将其插入队列中。我们插入2但是因为它的indegree将变为0。
<强>伪代码强>:
G = G^t
Q = a FIFO queue
push all nodes with indegree 0 in Q
set l(v) = 0 for all nodes with indegree 0
indegree(v) = how many edges are going into node v
while not Q.Empty():
x = Q.Pop()
for all nodes v reachable from x:
if indegree[v] > 0:
indegree[v] = indegree[v] - 1
if indegree[v] == 0:
Q.Push(v)
l[v] = l[x] + 1
您也可以使用DFS来计算递归返回后每个节点的值,如下所示:
value(v) = 1 + max{value(c), c a child of v}
请注意,DFS不在转置图上,因为我们让递归以拓扑排序顺序处理遍历。
答案 1 :(得分:1)
我们假设您的拓扑类型为G
。然后您可以按相反的顺序考虑顶点:如果您有u -> v
边缘,则v
在排序前u
之前。
如果您使用此订单循环节点,则如果没有传出边缘l(u) = 0
,请l(u) = 1 + max(l(v), for each v such that there is an edge (u, v))
。这是最佳的,并为您提供O(|V| + |E|)
算法来解决此问题。
证明留作练习。 :d