spfa判断负环

思路:

(1)负环:区别于正环,在求最短路过程中,正环会绕路,故不会被讨论,而负环会不断让路总权更短,会让算法不断循环;

(2)于是考虑统计spfa最短路算法走过的路径数,如果路径数超过合理值n - 1,说明必然存在负环;

(3)于是对spfa算法做适当修改,

  1. 一方面为防止1到不了负环,于是率先将所有点都提前放进队列中;
  2. 另一方面在更新距离时统计该路径边数;
  3. 由于只要存在负环,就会不断循环,所以无需将dist[]初始化。

代码:

#include

using namespace std;

const int N = 150000;

int n,m;
int h[N],st[N],e[N],ne[N],idx,dist[N],w[N],cnt[N];

void add(int a,int b,int c)
{
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++;
}

bool spfa()
{
    queue q;
    for(int i = 1;i <= n;i ++)  
    {
        q.push(i);
        st[i] = 1;
    }
        
    
    while(!q.empty())
    {
        auto t = q.front();
        q.pop();
        
        st[t] = 0;
        
        for(int i = h[t];i != -1;i = ne[i])
        {
            int j = e[i];
            
            if(dist[j] > dist[t] + w[i])
            {
                dist[j]  = dist[t] + w[i];
                cnt[j] = cnt[t] + 1;
                if(cnt[j] >= n) return true;
                if(!st[j])
                {
                    q.push(j);
                    st[j] = 1;
                }
            }
        }
    }
    
    return false;
    
}

int main()
{
    
    memset(h,-1,sizeof h);
    cin >> n >> m;
    
    while(m --)
    {
        int a,b,c;
        cin >> a >> b >> c;
        
        add(a,b,c);
    }
    
    if(spfa()) printf("Yes");
    else puts("No");
    
    return 0;
}

你可能感兴趣的:(算法)