未加权无向图中的最长路径
Longest path in unweighted undirected graph
以这张图为参考假设我想要 0 到 5 之间的最长路径。
那就是:0->1->3->2->4->6->5
有什么好的算法吗?我已经搜索过,但没有找到任何我能理解的东西。
我发现了很多最短路径算法 (0->1->2->4->6->5),并且我已经成功地实现了它们。
也许我是问题所在,但我不这么认为:)
欢迎任何帮助
这个问题是 NP-Hard 问题(从哈密顿路径到你的问题有一个简单的归约,并且已知哈密顿路径搜索是 NP-hard)。这意味着这个问题没有多项式解(除非P = NP)。
如果需要精确解,可以使用动态规划(状态数为指数):状态为(mask of visited vertices, last_vertex)
,值为true或false。如果 last_vertex
和新顶点之间有一条边,则过渡是添加一个不在 mask
中的新顶点。它具有 O(2^n * n^2)
时间复杂度,仍然优于 O(n!)
回溯。
这是一个动态规划解决方案的伪代码:
f = array of (2 ^ n) * n size filled with false values
f(1 << start, start) = true
for mask = 0 ... (1 << n) - 1:
for last = 0 ... n - 1:
for new = 0 ... n - 1:
if there is an edge between last and new and mask & (1 << new) == 0:
f(mask | (1 << new), new) |= f(mask, last)
res = 0
for mask = 0 ... (1 << n) - 1:
if f(mask, end):
res = max(res, countBits(mask))
return res
还有一点关于从哈密顿路径到这个问题的简化:
def hamiltonianPathExists():
found = false
for i = 0 ... n - 1:
for j = 0 ... n - 1:
if i != j:
path = getLongestPath(i, j) // calls a function that solves this problem
if length(path) == n:
found = true
return found
这是一个 Java 实现(我没有正确测试,所以它可能包含错误):
/**
* Finds the longest path between two specified vertices in a specified graph.
* @param from The start vertex.
* @param to The end vertex.
* @param graph The graph represented as an adjacency matrix.
* @return The length of the longest path between from and to.
*/
public int getLongestPath(int from, int to, boolean[][] graph) {
int n = graph.length;
boolean[][] hasPath = new boolean[1 << n][n];
hasPath[1 << from][from] = true;
for (int mask = 0; mask < (1 << n); mask++)
for (int last = 0; last < n; last++)
for (int curr = 0; curr < n; curr++)
if (graph[last][curr] && (mask & (1 << curr)) == 0)
hasPath[mask | (1 << curr)][curr] |= hasPath[mask][last];
int result = 0;
for (int mask = 0; mask < (1 << n); mask++)
if (hasPath[mask][to])
result = Math.max(result, Integer.bitCount(mask));
return result;
}
以这张图为参考假设我想要 0 到 5 之间的最长路径。
那就是:0->1->3->2->4->6->5
有什么好的算法吗?我已经搜索过,但没有找到任何我能理解的东西。 我发现了很多最短路径算法 (0->1->2->4->6->5),并且我已经成功地实现了它们。 也许我是问题所在,但我不这么认为:)
欢迎任何帮助
这个问题是 NP-Hard 问题(从哈密顿路径到你的问题有一个简单的归约,并且已知哈密顿路径搜索是 NP-hard)。这意味着这个问题没有多项式解(除非P = NP)。
如果需要精确解,可以使用动态规划(状态数为指数):状态为(mask of visited vertices, last_vertex)
,值为true或false。如果 last_vertex
和新顶点之间有一条边,则过渡是添加一个不在 mask
中的新顶点。它具有 O(2^n * n^2)
时间复杂度,仍然优于 O(n!)
回溯。
这是一个动态规划解决方案的伪代码:
f = array of (2 ^ n) * n size filled with false values
f(1 << start, start) = true
for mask = 0 ... (1 << n) - 1:
for last = 0 ... n - 1:
for new = 0 ... n - 1:
if there is an edge between last and new and mask & (1 << new) == 0:
f(mask | (1 << new), new) |= f(mask, last)
res = 0
for mask = 0 ... (1 << n) - 1:
if f(mask, end):
res = max(res, countBits(mask))
return res
还有一点关于从哈密顿路径到这个问题的简化:
def hamiltonianPathExists():
found = false
for i = 0 ... n - 1:
for j = 0 ... n - 1:
if i != j:
path = getLongestPath(i, j) // calls a function that solves this problem
if length(path) == n:
found = true
return found
这是一个 Java 实现(我没有正确测试,所以它可能包含错误):
/**
* Finds the longest path between two specified vertices in a specified graph.
* @param from The start vertex.
* @param to The end vertex.
* @param graph The graph represented as an adjacency matrix.
* @return The length of the longest path between from and to.
*/
public int getLongestPath(int from, int to, boolean[][] graph) {
int n = graph.length;
boolean[][] hasPath = new boolean[1 << n][n];
hasPath[1 << from][from] = true;
for (int mask = 0; mask < (1 << n); mask++)
for (int last = 0; last < n; last++)
for (int curr = 0; curr < n; curr++)
if (graph[last][curr] && (mask & (1 << curr)) == 0)
hasPath[mask | (1 << curr)][curr] |= hasPath[mask][last];
int result = 0;
for (int mask = 0; mask < (1 << n); mask++)
if (hasPath[mask][to])
result = Math.max(result, Integer.bitCount(mask));
return result;
}