D03 最短路 Bellman-Ford 算法 spfa 算法 判负环

视频链接:https://www.bilibili.com/video/BV1uL4y1N7Tb

Luogu P3385 【模板】负环

//Ford 判负环 740ms
#include <cstring> #include <iostream> #include <algorithm> using namespace std; const int inf=0x3f3f3f3f; const int N=2010,M=6010; int n,m; int to[M],ne[M],w[M],h[N],tot; int d[N]; void add(int a,int b,int c){ to[++tot]=b;w[tot]=c; ne[tot]=h[a];h[a]=tot; } bool ford(){ memset(d,inf,sizeof d); d[1]=0; bool flag; //是否松弛 for(int i=1;i<=n;i++){ //跑n轮 flag=false; for(int u=1;u<=n;u++){ //n个点 if(d[u]==inf)continue; for(int j=h[u];j;j=ne[j]){ int v=to[j]; if(d[v]>d[u]+w[j]){ d[v]=d[u]+w[j]; flag=true; } } } if(!flag)break; } return flag; //第n轮=true,有负环 } int main(){ int T; scanf("%d",&T); while(T--){ tot=0; memset(h,0,sizeof(h)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); if(w>=0)add(v,u,w);; } puts(ford()?"YES":"NO"); } return 0; }
//BFS_spfa 判负环 530ms
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=2010,M=6010;
int n,m;
int to[M],ne[M],w[M],h[N],tot;
int d[N],cnt[N],vis[N];

void add(int a,int b,int c){
  to[++tot]=b;w[tot]=c;
  ne[tot]=h[a];h[a]=tot;
}
bool spfa(){ //判负环
  memset(d,0x3f,sizeof d); 
  memset(vis,0,sizeof vis);
  memset(cnt,0,sizeof cnt);
  queue<int>q; 
  q.push(1); vis[1]=1; d[1]=0; 
  while(q.size()){
    int u=q.front();q.pop();vis[u]=0;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i];
      if(d[v]>d[u]+w[i]){
        d[v]=d[u]+w[i];
        cnt[v]=cnt[u]+1; 
        if(cnt[v]>=n)return 1;//判边数
        if(!vis[v])q.push(v),vis[v]=1;
      }
    }
  }
  return 0;
}
int main(){
  int T; scanf("%d",&T);
  while(T--){
    tot=0; memset(h,0,sizeof(h));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
      int u,v,w;
      scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);
      if(w>=0)add(v,u,w);;
    }
    puts(spfa()?"YES":"NO");
  }
  return 0;
}
//BFS_spfa 判负环 690ms
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=2010,M=6010;
int n,m;
int to[M],ne[M],w[M],h[N],tot;
int d[N],cnt[N],vis[N];

void add(int a,int b,int c){
  to[++tot]=b;w[tot]=c;
  ne[tot]=h[a];h[a]=tot;
}
bool spfa(){ //判负环
  memset(d,0x3f,sizeof d); 
  memset(vis,0,sizeof vis);
  memset(cnt,0,sizeof cnt);
  queue<int>q;
  q.push(1); vis[1]=1; d[1]=0; 
  while(q.size()){
    int u=q.front();q.pop();vis[u]=0;
    for(int i=h[u];i;i=ne[i]){
      int v=to[i];
      if(d[v]>d[u]+w[i]){
        d[v]=d[u]+w[i];
        if(++cnt[v]>n)return 1;//判点数
        if(!vis[v])q.push(v),vis[v]=1;
      }
    }
  }
  return 0;
}
int main(){
  int T; scanf("%d",&T);
  while(T--){
    tot=0; memset(h,0,sizeof(h));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
      int u,v,w;
      scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);
      if(w>=0)add(v,u,w);;
    }
    puts(spfa()?"YES":"NO");
  }
  return 0;
}

 

//DFS_spfa 判负环 会卡点 #9
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=2010,M=6010;
int n,m;
int to[M],ne[M],w[M],h[N],tot;
int d[N],vis[N];

void add(int a,int b,int c){
  to[++tot]=b;w[tot]=c;
  ne[tot]=h[a];h[a]=tot;
}
bool spfa(int u){ //判负环
  vis[u]=1;
  for(int i=h[u];i;i=ne[i]){
    int v=to[i];
    if(d[v]>d[u]+w[i]){
      d[v]=d[u]+w[i];
      if(vis[v]||spfa(v))return 1;
    }
  }
  vis[u]=0;
  return 0;
}
int main(){
  int T; scanf("%d",&T);
  while(T--){
    tot=0; memset(h,0,sizeof(h));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
      int u,v,w;
      scanf("%d%d%d",&u,&v,&w);
      add(u,v,w);
      if(w>=0)add(v,u,w);;
    }
    memset(d,0x3f,sizeof d);d[1]=0;
    memset(vis,0,sizeof vis);
    puts(spfa(1)?"YES":"NO");
  }
  return 0;
}

 

posted @ 2022-05-28 13:09  董晓  阅读(954)  评论(0编辑  收藏  举报