Bellman-Ford的队列优化
Bellman-Ford算法的另一种优化:每次仅对最短路程发生变化的点的相邻边执行松弛操作。
每次选取队首顶点u,对顶点u的所有出边进行松弛,例如u->v的边,如果通过u->v这条边使得源点到顶点v的最短路变短,
且顶点v不在当前队列中,就将v放入队尾。
需要注意的是,相同的点不能再次入队,所以我们需要一数组来判断是否已在队列里。
在对顶点u的所有出边松弛完毕后,就将顶点u出队。接下来不断取出新点再进行如上操作,直至对了为空。
测试用例:
5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4
4 5 5
5 3 6
first line:n,m分别为顶点个数和边数,接下来是m行,x,y,z表示x到y边的权值。
out :0 2 5 9 9
纯c版:代码如下:
#include<bits/stdc++.h>
using namespace std;
int main ()
{
int n,m,k;
int u[8],v[8],w[8];
int first[6],next[8];
int dis[6],book[6];
int que[101]= {0},head=1,tail=1;
int inf=99999999;
cin>>n>>m;
for (int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;
memset(book,0,sizeof(book));
memset(first,-1,sizeof(first));
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i]]=i;
}
que[tail]=1;
tail++;
book[1]=1;
while(head<tail)
{
k=first[que[head]];
while(k!=-1)
{
if(dis[v[k]]>dis[u[k]]+w[k])
{
dis[v[k]]=dis[u[k]]+w[k];
if(book[v[k]]==0)
{
que[tail]=v[k];
tail++;
book[v[k]]=1;
}
}
k=next[k];
}
book[que[head]]=0;
head++;
}
for (int i=1; i<=n; i++)
printf("%d ",dis[i]);
return 0;
}
c++版:这个算法部分人称SPFA
算法
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
int matrix[100][100]; // 邻接矩阵
bool visited[100]; // 标记数组
int dist[100]; // 源点到顶点 i 的最短距离
int path[100]; // 记录最短路的路径
int enqueue_num[100]; // 记录入队次数
int vertex_num; // 顶点数
int edge_num; // 边数
int source; // 源点
bool SPFA()
{
memset(visited, 0, sizeof(visited));
memset(enqueue_num, 0, sizeof(enqueue_num));
for (int i = 0; i < vertex_num; i++)
{
dist[i] = INT_MAX;
path[i] = source;
}
queue<int> Q;
Q.push(source);
dist[source] = 0;
visited[source] = 1;
enqueue_num[source]++;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
visited[u] = 0;
for (int v = 0; v < vertex_num; v++)
{
if (matrix[u][v] != INT_MAX) // u 与 v 直接邻接
{
if (dist[u] + matrix[u][v] < dist[v])
{
dist[v] = dist[u] + matrix[u][v];
path[v] = u;
if (!visited[v])
{
Q.push(v);
enqueue_num[v]++;
if (enqueue_num[v] >= vertex_num)
return false;
visited[v] = 1;
}
}
}
}
} // while (!Q.empty())
return true;
}
void Print()
{
for (int i = 0; i < vertex_num; i++)
{
if (i != source)
{
int p = i;
stack<int> s;
cout << "顶点 " << source << " 到顶点 " << p << " 的最短路径是: ";
while (source != p) // 路径顺序是逆向的,所以先保存到栈
{
s.push(p);
p = path[p];
}
cout << source;
while (!s.empty()) // 依次从栈中取出的才是正序路径
{
cout << "--" << s.top();
s.pop();
}
cout << " 最短路径长度是:" << dist[i] << endl;
}
}
}
int main()
{
cout << "请输入图的顶点数,边数,源点:";
cin >> vertex_num >> edge_num >> source;
for (int i = 0; i < vertex_num; i++)
for (int j = 0; j < vertex_num; j++)
matrix[i][j] = (i != j) ? INT_MAX : 0; // 初始化 matrix 数组
cout << "请输入" << edge_num << "条边的信息:\n";
int u, v, w;
for (int i = 0; i < edge_num; i++)
{
cin >> u >> v >> w;
matrix[u][v] = w;
}
if (SPFA())
Print();
else
cout << "Sorry,it have negative circle!\n";
return 0;
}