设G =(V,E)是具有节点v_1,v_2,...,v_n的有向图。如果G具有以下属性,我们说G是有序图。
给出一个有效的算法,该算法采用有序图G并返回从v_1开始并以v_n结束的最长路径的长度。
如果你想看到漂亮的乳胶版本:here
我的尝试:
动态编程。 Opt(i)= max {Opt(j)} + 1.对于所有j,这样的j可以从i到达。
是否有更好的方法可以做到这一点?我认为即使有记忆,我的算法仍然是指数级的。 (这只是我在网上找到的旧期中期评论)
答案 0 :(得分:2)
你的方法是对的,你必须做
Opt(i) = max {Opt(j)} + 1} for all j such that j is reachable from i
但是,只有在没有记忆的情况下运行它才会呈现指数。通过memoization,您将获得每个节点j,j>的memoized最佳值。我,当你在节点i。
对于最坏情况的复杂性,让我们假设每两个可以连接的节点都是连接的。这意味着,v_1
与(v_2, v_3, ... v_n)
相关联; v_i
与(v_(i+1), v_(i+2), ... v_n)
相关联。
顶点数(V
)= n
因此,边数(E
)= n*(n+1)/2 = O(V^2)
让我们将注意力集中在顶点v_k
上。对于这个顶点,我们必须经历已经导出的(n-k)
节点的最佳值。
直接到达v_k
的方式数量=(k-1)
因此最坏情况时间复杂度=> sigma((k-1)*(n-k)) from k=1 to k=n
,这是幂2的多项式的sigma,因此会导致O(n^3)
时间复杂度。
简单地说,最坏的情况时间复杂度是O(n^3) == O(V^3) == O(E) * O(V) == O(EV)
。
答案 1 :(得分:1)
由于第一个属性,这个问题可以解决O(V ^ 2)甚至更好的O(E),其中V是顶点数,E是边数。实际上,它使用的动态编程方法与您提供的方法非常相似。设opt [i]是v_1到v_i的最长路径的长度。然后
opt[i] = max(opt[j]) + 1 where j < i and we v_i and v_j is connected,
using this equation, it can be solved in O(V^2).
更好的是,我们可以用另一种顺序解决这个问题。
int LongestPath() {
for (int v = 1; v <= V; ++v) opt[v] = -1;
opt[1] = 0;
for (int v = 1; v <= V; ++v) {
if (opt[v] >= 0) {
/* Each edge can be visited at most once,
thus the runtime time is bounded by |E|.
*/
for_each( v' can be reached from v)
opt[v'] = max(opt[v]+1, opt[v']);
}
}
return opt[V];
}