SPFA判断负环(优化)

版权声明:本文为博主原创文章,转载需标明原创地址 https://blog.csdn.net/qq_42321579/article/details/82860755

先放一张图加深理解负环

所谓负环,即权值之和为负值的环

此图中执行SPFA会进入负环的死循环(每次加边后都比原来值小)

故应cnt[ ]记录下每个点遍历次数

若大于总点数,则存在负环

例题 :洛谷—负环模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 100010
#define INF 0x3f3f3f3f 
struct edge
{
    int to,w;//保存边的信息,包括边的终点以及权值
};
int cnt[M];//用于记录该点入队次数 
int flag = 0;
long long dis[M];  //最短距离的估计值(当前该点的最短距离)
bool inq[M]; //标记该点是否在队列之中
vector<edge> g[M]; //利用一个vector保存,g[i]表示以i为起点的所有边的信息
int n,m,ee;
void spfa(int u)
{
    for(int i = 0;i <= n;i++) //初始化
    {
        dis[i] = INF; //将估计值都初始化为INF
        inq[i] = false;
        cnt[i] = 0; //初始化为不在队列中
    }
    dis[u] = 0; //起点的估计值直接就是0
    inq[u] = true; //加入队列并进行标记
    queue<int> q;
    q.push(u);
    while(!q.empty())
    {
        u = q.front();
        inq[u] = false;
        q.pop();
        for(int i = 0;i < g[u].size();i++)
        {
            int v = g[u][i].to; //找出这条边对应的终点
            int w = g[u][i].w;  //这条边对应的权值
            if(cnt[v] > n){//此处判负环,由于入队次数大于总点数,则进入负环的死循环 
            	flag = 1;
            	return ;
            }
            if(dis[v] > dis[u]+w) //如果终点的最短距离比起点的最短距离加上这条边的权值大 那么就更新
            {
                dis[v] = dis[u]+w;
                cnt[v] = cnt[u] + 1;//一处优化,计算是否进入负环死循环中 
                if(cnt[v] > n){
            		flag = 1;
            		return ;
                }
                if(!inq[v]) //如果v点的最短距离有所更新并且不在队列中,就将其加入队列。
                {           //否则就不需要重复加入队列增加不必要的操作。
                    inq[v] = true;  //加入队列并标记
                    q.push(v);
                }
            }
        }
    }
}
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
    	flag = 0;
    	scanf("%d%d",&n,&m);
        for(int i = 0;i <= 2005;i++) //清空vector避免多kase相互影响
            g[i].clear();
        for(int i = 0;i < m;i++)
        {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            edge e;
            if(c >= 0){
            	e.to = b;e.w = c;
            	g[a].push_back(e);
            	e.to = a;
            	g[b].push_back(e);
            }else{
            	e.to = b;e.w = c;
            	g[a].push_back(e);
        	}
        }
        spfa(1);
  		if(flag){
  			printf("YE5\n");
          }else{
          	printf("N0\n");
          }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42321579/article/details/82860755