我正在实现一个k最短的顶点不相交路径算法,需要一个 快速算法找到最短路径。有负重,所以我不能 使用dijkstra和bellman-ford是O(ne)。在一篇论文中,我最近读了作者 使用所谓的SPFA算法来查找图中的最短路径 负重 - 根据它们 - 具有O(e)的复杂性。声音 有趣,但我似乎无法找到有关算法的信息。 Appearently 这个:http://en.cnki.com.cn/Article_en/CJFDTOTAL-XNJT402.015.htm是原作 纸,但我无法访问它。
有没有人有这个算法的良好信息或实施? 此外,是否有任何k-shortest顶点不相交路径问题的来源? 我什么都找不到。
谢谢!
答案 0 :(得分:2)
SPFA算法是对Bellman-Ford的优化。在Bellman-Ford期间,我们只是盲目地通过| V |的每个边缘轮次,在SPFA中,维护一个队列以确保我们只检查那些放松的顶点。这个想法类似于Dijkstra的。它也与BFS具有相同的风格,但是一个节点可以多次放入队列。
首先将源添加到队列中。然后,当队列不为空时,从队列中弹出一个顶点u,我们查看其所有邻居v。如果v的距离发生变化,我们将v添加到队列中(除非它已经在队列中)
作者证明SPFA通常很快(\ Theta(k | E |),其中k <2)。
这是来自wikipedia in Chinese的伪代码,您可以在其中找到C中的实现。
Procedure SPFA;
Begin
initialize-single-source(G,s);
initialize-queue(Q);
enqueue(Q,s);
while not empty(Q) do
begin
u:=dequeue(Q);
for each v∈adj[u] do
begin
tmp:=d[v];
relax(u,v);
if (tmp<>d[v]) and (not v in Q) then
enqueue(Q,v);
end;
end;
End;
答案 1 :(得分:0)
找出最短路径实际上是一个很好的算法。它也被认为是由队列重写的Bellmen-Ford算法。但在我看来,它更喜欢BFS。它的复杂性是O(ke)(e表示边数,k≈2)。尽管我根本无法理解它,但它在大多数问题上都很快,特别是当只有少数边缘时。
Func spfa(start, to) {
dis[] = {INF}
visited[] = false
dis[start] = 0
// shortest distance
visited[start] = true
queue.push(start)
// push start point
while queue is not empty {
point = queue.front()
queue.pop()
visited[point] = false
// marked as unvisited
for each V from point {
dis[V] = min(dis[V],dis[point] + length[point, V]);
if visited[V] == false {
queue.push(V)
visited[V] = true
}
}
}
return dis[to]
}
获得路径也很容易更多 希望我能帮助你(● - ●)来自OIer
答案 2 :(得分:0)
贝尔曼福德can handle negative edges。
SPFA和Bellman-ford基本是同一回事,因此具有相同的最坏情况复杂度。
SPFA是对Bellman-ford的优化。
看看我的personal implementation SPFA C ++ for PS:
using namespace std;
const int INF = INT_MAX / 4;
struct node { int v, w; };
vector<int> SPFA(int max_v, int start_v, vector<vector<node>>&adj_list) {
vector<int> min_dist(max_v + 1, INF);
min_dist[start_v] = 0;
queue<node> q; q.push({ start_v,0 });
queue<int> qn; qn.push(0);
while (q.size()) {
node n = q.front(); q.pop();
int nn = qn.front(); qn.pop();
if (nn >= max_v) { printf("-1\n"); exit(0); }//negative cycle
if (min_dist[n.v] < n.w) continue;
min_dist[n.v] = n.w;
for (node adj : adj_list[n.v]) {
if (min_dist[adj.v] <= adj.w + n.w) continue;
min_dist[adj.v] = adj.w + n.w;
q.push({ adj.v, adj.w + n.w }), qn.push(nn + 1);
}
}
return min_dist;
}
int main()
{
// N: vertex cnt, M: edge cnt
int N, M; scanf("%d%d", &N, &M);
vector<vector<node>> adj_list(N + 1);
for (int i = 0; i < M; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w); // edge u->v, w:weigt
adj_list[u].push_back({ v,w });
//adj_list[v].push_back({ u,w }); in case of undirected graph
}
// shortest path from '1' to 'N'
vector<int> dist = SPFA(N, 1, adj_list);
printf("%d\n", dist[N]);
return 0;
}