前面说过dijkstra不能对负权边进行操作,而现在介绍的SPFA算法是对dijkstra的一种改进,它可以对负权边进行处理,而且还可以判断是否存在负环。
如果存在一个点进入队列的次数超过N次,则存在负环。
下面SPFA的代码可以代替dijkstra的代码:
int SPFA(int star, int end, int n)
{
dis[star] = 0;
Q.push(star);
used[star] = true;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
used[u] = false;
for (int v = 0; v < n; v++)
{
if (map[u][v] != INF && dis[u] + map[u][v] < dis[v]) //松弛操作
{
dis[v] = dis[u] + map[u][v];
if (!used[v])
{
used[v] = true;
Q.push(v);
}
}
}
}
return dis[end];
}
下面是HDOJ-1874用SPFA改写的代码:
#include <iostream>
#include <queue>
using namespace std;
const int MAXN = 200 + 10;
int map[MAXN][MAXN];
int dis[MAXN]; //保存所有点到起点的最小距离
bool used[MAXN];
const INF = 0x3ffffff;
queue <int > Q;
void init(int n)
{
for (int i = 0; i < n; i++)
{
dis[i] = INF;
for (int j = 0; j < n; j++)
{
map[i][j] = INF;
}
}
memset (used,false,sizeof(used));
while (!Q.empty())
{
Q.pop();
}
}
int SPFA(int star, int end, int n)
{
dis[star] = 0;
Q.push(star);
used[star] = true;
while (!Q.empty())
{
int u = Q.front();
Q.pop();
used[u] = false;
for (int v = 0; v < n; v++)
{
if (map[u][v] != INF && dis[u] + map[u][v] < dis[v]) //松弛操作
{
dis[v] = dis[u] + map[u][v];
if (!used[v])
{
used[v] = true;
Q.push(v);
}
}
}
}
if (dis[end] == INF)
{
return -1;
}
else
{
return dis[end];
}
}
int main()
{
int n,m;
while(cin>>n>>m)
{
int a,b,c;
init(n);
for (int i = 0; i < m; i++)
{
cin>>a>>b>>c;
if(c < map[a][b]) //考虑如果有重边,用最小的进行构造图(好坑爹啊!!)
{
map[a][b] = c;
map[b][a] = c;
}
}
int s,t;
cin>>s>>t;
cout<<SPFA(s, t, n)<<endl;
}
return 0;
}