AcWing 852:spfa判断负环 ← 链式前向星存图

82 篇文章 3 订阅
73 篇文章 1 订阅

【题目来源】
https://www.acwing.com/problem/content/854/

【题目描述】
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你判断图中是否存在负权回路。

【输入格式】
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

【输出格式】
如果图中存在
负权回路,则输出 Yes,否则输出 No。

【数据范围】
1≤n≤2000,
1≤m≤10000,
图中涉及边长绝对值均不超过 10000。

【输入样例】
3 3
1 2 -1
2 3 4
3 1 -4

【输出样例】
Yes

【算法分析】
● SPFA 算法,全称为
Shortest Path Faster Algorithm,是求解单源最短路径问题的一种常用算法,它可以处理有向图或者无向图,边权可以是正数、负数,但是不能有负环。
● Dijkstra 算法不能处理负权边。SPFA 算法能处理负权边。
● SPFA 算法是
判断负环的常用算法,其实现如下: 在更新 dis[i] 时,我们顺带维护一个 cnt[i] 数组,该数组用来存放最短路的边数。如果 cnt[i]≥n 时,说明图中有 n+1 个点,而题目一共给了 n 个点,说明一定存在环。而 SPFA 算法更新的要求是距离变短,因此这个环一定是负环。 但是从原点开始可能走不到负环,我们需要初始时把所有的点都放入队列中。
● 链式前向星:https://blog.csdn.net/hnjzsyjyj/article/details/127190456
● 本题代码与 
https://blog.csdn.net/hnjzsyjyj/article/details/138425339 及其类似。

【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;
int val[maxn],e[maxn],ne[maxn],h[maxn],idx;
int dis[maxn],cnt[maxn];
bool st[maxn];
int n,m;

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

int 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(dis[j]>dis[t]+val[i]) {
                dis[j]=dis[t]+val[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n) return true;
                if(!st[j]) {
                    Q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}

int main() {
    cin>>n>>m;
    memset(h,-1,sizeof h);
    while(m--) {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }

    if(spfa()) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;

    return 0;
}


/*
in:
3 3
1 2 -1
2 3 4
3 1 -4

out:
Yes
*/



【参考文献】
https://zhuanlan.zhihu.com/p/353019102
https://www.acwing.com/solution/content/47218/
https://blog.csdn.net/hnjzsyjyj/article/details/138425339
https://www.acwing.com/video/284/



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值