spfa判断负环

题目描述:

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数

请你判断图中是否存在负权回路。

输入格式:

第一行包含整数 n 和 m。

接下来 m行每行包含三个整数 x,y,z表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式:

如果图中存在负权回路,则输出 Yes,否则输出 No

判断有没有负环,其实我们这里用一个数组存放到达每个点的边数,然后判断它的边数是否是大于等于顶点边数的,如果成立,那么就必然存在环,反之则没有。(因为n个顶点没有环的话,边最多就是n - 1)

#include <iostream>
#include <cstring>
#include <queue>
//需要用到队列,以及一个初始化函数:memset()
using namespace std;
const int N = 10010;
int n,m;
int e[N],h[N],ne[N],w[N],idx;
//邻接表的存储,有兴趣的可以去了解一下,w数组存储权值
int dis[N],cnt[N];
//dis数组存储到达点的距离,cnt数组存储到达每个点的边数
bool st[N];
//st数组用来标记队列里面的元素,如果在队列里面就为true,反之则为false
void add(int a,int b,int c)//邻接表的存储模板
{
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx ++;
}
bool spfa()//这也是一个spfa的模板
{
    queue<int> q;//声明一个队列
    for(int i = 1; i <= n; i ++ )
    {
        st[i] = true;
        q.push(i);
        //将每个元素都存入队列,并且标记
    }
    while (q.size())//只要队列不为空,就继续执行
    {
        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] + w[i])
            {
                dis[j] = dis[t] + w[i];
                cnt[j] = cnt[t] + 1;//记得边数加1
                if(cnt[j] >= n) return true;
                //如果边数大于等于n,则说明存在环,返回true即可(为什么返回这个,你看下面的输出 
                //判断条件就懂了)
                if(!st[j])
                {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
    return false;//返回这个就说明不存在环
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof(h));//记得初始化h数组
    while (m --)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        //存图
    }
    if(spfa()) printf("Yes\n");//返回true说明有环,输出Yes
    else printf("No\n");//否则无环输出No
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薇尔莉特伊芙加登

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值