P3385 【模板】负环
负环
一个边权之和为负的环。
eg:
负边权为单向边(题目)
不然 只要存在负边就会有负环
如果有负环,最短路为-∞
所以可以卡内存、卡时间、爆了队列就判定有负环
BFS
WAY1:
https://blog.csdn.net/weixin_44620025/article/details/87461886
bfs*1原理
- 如果一个图有负环,那么每跑一圈负环,路径长度就会变小。
那么可以无限地跑这个负环,就形成了死循环。
=>当这个图是一条直线时,1 - > n的最短路过n个点 - 一个n个点的图的最短路最多只会经过n个点。如果超过n个点那么就会有点是重复走的。
- 负环上的点就是重复走的。所以只要判断走到一个点的最短路中经过的点数是否超过n即可。
bfs*1.代码
719ms , 800.00KB
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=2010,maxm=3010;
struct node{
int from,to,w,next;
}edge[maxm*2];
int head[maxn],tot=0;
int T,n,m;
int dis[maxn];
bool flag[maxn];
int circle[maxn];
//一个数组circle[i]示从点1到点i的最短路经过的点的个数。
void add_edge(int x,int y,int z)
{
edge[++tot].from=x;
edge[tot].to=y;
edge[tot].next=head[x];
edge[tot].w=z;
head[x]=tot;
}
bool spfa(){
queue<int> q;
q.push(1);
circle[1]=1;
while(!q.empty()){
int find=q.front();
q.pop();
flag[find]=false;
for(int i=head[find];i;i=edge[i].next){
int u=edge[i].from;
int v=edge[i].to;
int w=edge[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!flag[v]){
circle[v]=circle[u]+1;
//当前v点最短路过点数为 u点的数量+1
if(circle[u]>n)return true;
//判断走到一个点的最短路中经过的点数是否超过n
q.push(v);
flag[v]=true;
}
}
}
}