点击查看代码
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#pragma warning(disable:4996)
const int maxn = 510; //最多不超过500个顶点
const int INF = 0x3fffffff; //表示无穷大
//SPFA伪代码
queue<int> q;
源点s入队
while (队列q非空) {
取出队首元素u;
for (遍历u的所有邻接边) {
if (d[u] + dis < d[v]) { //如果以u为中转点,可以使起点与v距离更短
d[v] = d[u] + dis; //更新d[v]
if (v不在队列中) {
将v入队;
if (v入队次数大于n-1) 则表示图中存在从源点出发的负环 算法返回false,然后根据题目要求存在负环时的情况进行处理
}
}
}
}
否则while循环结束后,算法返回true,表示图中不存在从源点出发的负环
//SPFA算法是Bellman的优化版本,解决单源最短路径(含有负边权),时间复杂度是O(ke),k是常数,很多情况下不超过2,e是边数
struct Node {
int v, dis; //邻接表的目标顶点,dis是边权
};
vector<Node> adj[maxn]; //邻接表存储图G
int n, d[maxn]; //顶点数,起点到各点的最短距离
int num[maxn]; //记录每个顶点的入队次数,如果事先知道图中不存在环,那么可以省略
bool inq[maxn]; //记录每个顶点是否存在队列中
bool SPFA(int s) { //起点是s
fill(num, num + maxn, 0); //初始时num[]全部为0,每个顶点入队次数为0
fill(inq, inq + maxn, false); //初始时inq[]全部为false,每个顶点都不在队列中
fill(d, d + maxn, INF); //初始时d[]全部为无穷大,表示顶点与各点都不相连
queue<int> q; //定义队列q
q.push(s); //起点入队
inq[s] = true; //设置起点在队列中
num[s]++; //起点入队次数加一
d[s] = 0; //起点与自己的距离为0
//主体部分
while (!q.empty()) { //当队列为空时,不需要再继续遍历,算法结束
int u = q.front(); //将队首顶点存入u中
q.pop(); //队首顶点出队后要手动删除
inq[u] = false; //u出队后,设置u不在队列中
for (int j = 0; j < adj[u].size(); j++) { //遍历u的所有邻接边v
int v = adj[u][j].v; //为了方便书写用v和dis记录邻接点和边u->v的边权
int dis = adj[u][j].dis;
if (d[u] + dis < d[v]) { //如果以u为中转点,可以使起点与v距离更短
d[v] = d[u] + dis; //更新d[v]
if (!inq[v]) { //如果v不在队列中
q.push(v); //将v入队
inq[v] = true; //设置v已在队列中
num[v]++; //v入队次数加一
//如果v入队次数大于n-1,则表示图中存在从源点出发的负环,算法返回false,然后根据题目要求存在负环时的情况进行处理
if (num[v] >= n) return false;
}
}
}
}
return true; //否则返回true,表示图中不存在从源点出发的负环
}