0
点赞
收藏
分享

微信扫一扫

spfa算法(c++)

玉字璧 2022-02-18 阅读 58

SPFA算法(对bellman - ford的优化)(适用于负权边且不能有负权回路)

一般情况下spfa算法也可以解决正权边问题,且时间比Dijkstrsa更快(但是如果出题人卡掉了spfa算法,就只能用Dijkstrsa算法了)

上一篇博客介绍了bellman_ford算法,建议两个算法一起看
区别:bellman_ford算法更新每一个点,而spfa算法只更新变小的点。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 1e5 + 10;
int n,m;
int h[N] , e[N] , w[N] , ne[N] , idx;
int dist[N];
bool st[N];

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

void spfa()
{
   queue<int>q;//存储每次更新的所有的点
   
   dist[1] = 0;
   q.push(1);
   st[1] = true;
   
   while(!q.empty())
   {
       int t = q.front();//每次从队列取出一个来更新所有它能够到达的点
       q.pop();
       st[t] = false;
       
       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];//更新操作
               
               if(!st[j])//如果队列里面没有这个点就入队
               {
                   q.push(j);
                   st[j] = true;
               }
           }
       }
   }
   
}

int main()
{
   cin>>n>>m;
   memset(dist,0x3f,sizeof dist);
   memset(h,-1,sizeof h);
   
   for(int i=0;i<m;i++)
   {
       int a,b,c;
       cin>>a>>b>>c;
       add(a,b,c);
   }
   
   spfa();
   
   if(dist[n] == 0x3f3f3f3f) cout<<"impossible";
   else cout<<dist[n];
   
   return 0;
}


除此之外,spfa算法还可以用来判断是否存在负环。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n,m;//n是点数,m是边数
int h[N] , e[N] , w[N] , ne[N] , idx;
int dist[N],cnt[N];
bool st[N];

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

bool spfa()
{
    queue<int>q;
    
    //这里不需要求最短路,所以不需要更新初始值。
    
    for(int i=1;i<=n;i++)//有可能从一号点到达不了负环,所以先将每个点都入队。
    {
        q.push(i);
        st[i] = true;
    }
    
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        st[t] = false;
        
        for(int i = h[t] ; i != -1 ; i = ne[i])
        {
            int j = e[i];
            if(cnt[j] >= n) return true;//如果有点入队的次数大于等于n,说明存在负权回路
            
            if(dist[j] > dist[t] + w[i])
            {
                dist[j] = dist[t] + w[i];
                if(!st[j])
                {
                    q.push(j);
                    cnt[j] ++;//入队一次就将这个点入对的次数加一
                    st[j] = true;
                }
            }
        }
    }
    return false;
}

int main()
{
    cin>>n>>m;
    
    memset(h,-1,sizeof h);
    for(int i=0;i<m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    
    if(spfa()) cout<<"Yes";
    else cout<<"No";
    
    return 0;
}

总结spfa

  1. 初始化第一个点
  2. 更新每个点的节点
举报

相关推荐

0 条评论