SPFA算法:首先源点到源点的距离为0,然后用源点对其他点进行松弛操作(更新操作),若松弛成功,表明源点到其的路径变小了,那么该点有可能能作为中间点松弛其他点,所以得将其入队列(如果它不在队列里面的话)某个点得到了松弛,如果它在队列里面,那么它能松弛的点会在接下的过程中得到松弛,如果它在这之前已经松弛了其他点,那么由于它受到了松弛,则那些它可以松弛的点将会进一步被松弛,所以它得重新入队列;如果没有负权值的边,那么松弛操作不会一直下去,当队列里的元素为空时,算法结束!
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define len 100
#define INF 9999999
int n,m,s,d,dis[len],vis[len],road[len][len],cot[len];
//n个点,m条边,s源点,d终点;dis[i]->s到i的最短距离,
//vis[i]判断i是否在队列中,road数组存图,cot[i]表示i进
//队列的次数,也就是i更新dis数组的次数
bool spfa()
{
int i,t;;
for (i = 1; i <= n; ++i)
dis[i] = INF;//初始时,源点到其他点的距离为无穷大
memset(vis,0,sizeof(vis));
memset(cot,0,sizeof(cot));
queue<int>q;
q.push(s);
dis[s] = 0;
vis[s] = 1;
while (!q.empty())
{
t = q.front();
q.pop();
vis[t] = 0;
++cot[t];
if (cot[t] > n)
return false;
for (i = 1; i <= n; ++i)
{
if (dis[i] > dis[t] + road[t][i])
/*
假设1,2之间存在负权值的边,如果1(或2)为源点,那么当i=2时,dis[2]更新(无穷大->负值),
2入队列;当2出队列,i=1时,dis[1]被更新(0->负值),1入队列,2被更新......那么对列将不会
为空
*/
{
dis[i] = dis[t] + road[t][i];
if (!vis[i])
{
q.push(i);
vis[i] = 1;
}
}
}
}
return true;
}
int main()
{
int i,j,u,v,w;
while (cin>>n>>m)
{
for (i = 1; i <= n; ++i)
{
for (j = 1; j <= n; ++j)
road[i][j] = i == j ? 0 : INF;
}
for (i = 1; i <= m; ++i)
{
scanf("%d%d%d",&u,&v,&w);
road[u][v] = road[v][u] = w;
}
scanf("%d%d",&s,&d);
if (spfa())
{
cout<<dis[d]<<endl;
}
else
cout<<"sorry"<<endl;
}
return 0;
}