D03 最短路 Bellman-Ford 算法 spfa 算法 P3385【模板】负环

D03 最短路 Bellman-Ford 算法 SPFA 算法——信息学奥赛算法_哔哩哔哩_bilibili

P3371 【模板】单源最短路径(弱化版) - 洛谷

1. d[] 维护点到根的最短路

2. vis[] 维护点是否在队中

3. 队列 <int> 维护队中点

4. 松弛:d[v]>d[u]+w

5. 点多次入队出队,直到最优

// spfa算法 O(m~nm)
#include<bits/stdc++.h>
using namespace std;

const int N=10010,M=500010,inf=(1<<31)-1;
int n,m,s,a,b,c;
int h[N],to[M],w[M],ne[M],tot;
void add(int a,int b,int c){
  to[++tot]=b;w[tot]=c;ne[tot]=h[a];h[a]=tot;
}
int d[N],vis[N];

void spfa(){
  for(int i=1;i<=n;i++) d[i]=inf; d[s]=0;
  queue<int>q; q.push(s); vis[s]=1; //在队中
  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(!vis[v]) q.push(v),vis[v]=1;
      }
    }
  }
}
int main(){
  cin>>n>>m>>s;
  for(int i=0;i<m;i++){
    scanf("%d%d%d",&a,&b,&c);
    add(a,b,c);
  }
  spfa();
  for(int i=1;i<=n;i++) printf("%d ",d[i]);
}

 

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 h[N],to[M],w[M],ne[M],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");
  }
}

 

//spfa 判负环 530ms
#include<bits/stdc++.h>
using namespace std;

const int N=2010,M=6010;
int n,m;
int h[N],to[M],ne[M],w[M],tot;
int d[N],vis[N],cnt[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); d[1]=0;
  memset(vis,0,sizeof vis);
  memset(cnt,0,sizeof cnt);
  
  queue<int>q; q.push(1); vis[1]=1; //在队中
  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(!vis[v]) q.push(v),vis[v]=1;
        cnt[v]=cnt[u]+1; //边数
        if(cnt[v]>=n) return 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");
  }
}

 

//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;
}

 

最短路 - OI Wiki

 

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