📅  最后修改于: 2023-12-03 14:49:55.469000             🧑  作者: Mango
负循环又称负环,是指在有向图中,存在一条从某个顶点开始经过若干边后回到该顶点的回路,并且其中所有边的权值之和为负数。
使用最短路径更快算法(SPFA)可以检测图中的负循环。
最短路径更快算法是一种单源最短路径算法,其基本思想是利用队列对图中所有节点进行松弛操作,直到每个节点的最短路径长度稳定下来。
具体实现过程如下:
如果经过一定次数的松弛操作后仍然有节点的dist被更新,则说明图中存在负循环。
以下代码为C++实现的SPFA算法,用于检测图中是否存在负循环:
#define INF 0x3f3f3f3f // INF为一个足够大的数
vector<pair<int,int> > edge[N]; // 存储边的数组
int dist[N], cnt[N]; // dist为起点到各点的最短距离,cnt为各点进入队列的次数
bool inq[N]; // 判断一个点是否在队列中
bool SPFA(int s) { // s为起点
memset(dist, INF, sizeof(dist)); // 距离数组初始化为INF
memset(cnt, 0, sizeof(cnt)); // 进入队列次数初始化为0
memset(inq, false, sizeof(inq)); // 判断是否在队列中初始化为false
queue<int> q;
q.push(s);
inq[s] = true;
dist[s] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int i = 0; i < edge[u].size(); i++) { // 遍历每个邻接点
int v = edge[u][i].first;
int w = edge[u][i].second;
if (dist[v] > dist[u] + w) { // 如果从当前点松弛到邻接点的距离更短
dist[v] = dist[u] + w;
cnt[v] = cnt[u]+1;
if (cnt[v] > n) return true; // 如果进入队列的次数超过n次,说明存在负环
if (!inq[v]) { // 如果邻接点不在队列中,则加入队列
q.push(v);
inq[v] = true;
}
}
}
}
return false; // 如果没有负环,返回false
}
以上代码中,N为最大节点数,n为图中节点个数。edge数组存储每个节点的所有邻接边,pair表示邻接的节点及边权。cnt数组用于记录每个节点进入队列的次数,如果某个节点进入队列的次数超过n次,则说明图中存在负循环。在每次对节点进行松弛操作后,需要将节点加入队列中,如果节点已经在队列中则不加入,防止重复遍历。