大家都知道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;
}