Bellman_Ford的负环

本文介绍Bellman算法及其改进版本SPFA。通过两种实现方式详细解释了如何利用Bellman算法进行单源最短路径计算及负环检测。第一种实现方式为经典的Bellman-Ford算法,第二种则采用DFS实现,主要关注是否存在负环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家都知道Bellman的优化版是SPFA
但是我还是偏向于叫Bellman
这是一种重要的负环判断法(同时维护单源最短路

//这里写代码片

struct node{
    int x,y,v;
};

struct Bellman{
    int n,m;
    vector<node> e;           //边列表 
    vector<int> G[N];        //每个结点所连边的编号 
    bool in[N];         //在对列中的标记 
    int pre[N];         //转移边 
    int dis[N];         //最短路 
    int cnt[N];         //入队次数

    void init(int n)
    {
        this->n=n;
        e.clear();
        for (int i=1;i<=n;i++) G[i].clear();
    }

    void add(int u,int w,int z)
    {
        e.push_back((node){u,w,z});
        m=e.size();
        G[u].push_back(m-1);
    }

    bool fuhuan(int s)
    {
        queue<int> Q;
        memset(in,0,sizeof(in));
        memset(cnt,0,sizeof(cnt));
        for (int i=1;i<=n;i++)    //虚拟一个超级源点
        {
            dis[i]=0;
            in[i]=1;
            Q.push(i);
        }

        while (!Q.empty())
        {
            int now=Q.front(); Q.pop();
            in[now]=0;

            for (int i=0;i<G[now].size();i++)
            {
                node way=e[G[now][i]];
                int v=way.y;
                if (dis[v]>dis[now]+way.v)
                {
                    dis[v]=dis[now]+way.v;
                    pre[v]=G[now][i];
                    if (!in[v])
                    {
                        Q.push(v);
                        in[v]=1; 
                        if (++cnt[v]>n) return 1;
                    }
                }
            }
        }
        return 0;
    }
};

上面给出的朴素的Bellman,
如果我们只关心是否有负环(弱化最短路的求解)
我们可以使用dfs版本的Bellman(使用率不高)

//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>

using namespace std;

const int N=200005;
const int mod=5000000;
struct node{
    int x,y,v,nxt;
};
node way[N<<1];
int st[N],tot=0;
int dis[N],n,m;
bool in[N],ff;

void add(int u,int w,int z)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}

void Bellman(int now)
{
    if (ff) return;                     //存在环 
    in[now]=1;
    for (int i=st[now];i;i=way[i].nxt)
        if (dis[way[i].y]>dis[now]+way[i].v&&ff==0)
        {
            dis[way[i].y]=dis[now]+way[i].v;
            if (in[way[i].y])
            {
                ff=1; return;
            } 
            else Bellman(way[i].y);
        }
    in[now]=0;                         //入栈状态 
    return;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        memset(st,0,sizeof(st));
        tot=0;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int u,w,z;
            scanf("%d%d%d",&u,&w,&z);
            add(u,w,z);
            if (z>=0) add(w,u,z);
        }
        memset(in,0,sizeof(in));             //访问记录 
        memset(dis,0,sizeof(dis));           //最短路 
        ff=0;
        for (int i=1;i<=n;i++)
        {
            Bellman(i);
            if (ff) break;
        }
        if (ff) printf("YE5\n");        //输出有毒 
        else printf("N0\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值