spfa-最短路-判断是否有负环

适用于有负权边的情况
时间复杂度O(mn)

dist[b] = min(dist[b], dist[a] + w)
只有当dist[a] 有变小的可能时, dist[b]才有变小的可能
通过队列进行更行可能会变小的路径

#include
#include
#include
#include
#include

using namespace std;

//邻接表存图
const int N = 100010;

int h[N], w[N], e[N], ne[N], idx;
int dist[N];
bool vis[N];


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

int n;

int spfa(){
    
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    queue<int>q;
    q.push(1);
    vis[1] = true;
    
    while(!q.empty()){
        int t = q.front();
        q.pop();
        // if(vis[t]) continue;
        
        vis[t] = false;
        
        
        //找到t的临边进行更新
        
        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(!vis[j]){
                    q.push(j);
                    vis[j] = true;
                }
            }
            
        }
    }
    
    return dist[n];
    
    
    
    
}

int main(){
    int m;
    
    cin>>n>>m;
    int x, y, z;
    memset(h, -1, sizeof h);
    for(int i = 0; i < m; i++){
        cin>>x>>y>>z;
        add(x,y,z);
    }
    
    int ans = spfa();
    
    if(ans > 0x3f3f3f3f/2){
        cout<<"impossible" << '\n';
        
    }else cout <<ans << '\n';
    
    return 0;
}

spfa - 判断是否有负环
通过cnt[]数组进行判断
cnt[]用来判断最短路的边数,当边数 >= n 说明在负环这里一直循环。
需要注意的是 负环不一定从1开始 ,即每个点都是起点,所以最初需要把每个点都加进去。

#include
#include
#include
#include
#include

using namespace std;

//邻接表存图
const int N = 100010;

int h[N], w[N], e[N], ne[N], idx;
int dist[N] ,cnt[N];
bool vis[N];


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

int n;

bool spfa(){
    
    memset(dist, 0x3f, sizeof dist);
    // dist[1] = 0;
    queue<int>q;
    for(int i = 1; i <= n; i++){
            q.push(i);
            vis[i] = true;
            cnt[i] = 0;
        
    }

    
    while(!q.empty()){
        int t = q.front();
        q.pop();
        // if(vis[t]) continue;
        
        vis[t] = false;
        
        //找到t的临边进行更新
        
        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(!vis[j]){
                    q.push(j);
                    vis[j] = true;
                }
            }
            
        }
    }
    
    return false;
    
    
    
    
}

int main(){
    int m;
    
    cin>>n>>m;
    int x, y, z;
    memset(h, -1, sizeof h);
    for(int i = 0; i < m; i++){
        cin>>x>>y>>z;
        add(x,y,z);
    }
    
    bool ans = spfa();
    
    if(ans){
        cout<<"Yes" << '\n';
        
    }else cout <<"No" << '\n';
    
    return 0;
}

你可能感兴趣的:(搜索与图论,图论,算法)