0
点赞
收藏
分享

微信扫一扫

洛谷P3385负环与SPFA算法

王老师说 2022-02-18 阅读 77

SPFA算法:

于是板子题又双叒叕应运而生:传送门

#include<bits/stdc++.h>
#define ff(i,s,e) for(int i=s;i<=e;i++)
#define fff(i,s,e) for(int i=s;i>=e;i--)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
    return x*f;
}
const int N=2010,M=3010,inf=0x3f3f3f3f;
int n,m;
int tal,head[N];
int dis[N];
int mark[N];//元素i被标记过几次
bool vis[N];//元素i是否在队列中
struct qwq{
    int to,nxt,w;
}a[M*2];
queue<int> q;
void add(int u,int v,int w){//链式前向星存储
    a[++tal].w=w;
    a[tal].to=v;
    a[tal].nxt=head[u];
    head[u]=tal;
}
bool spf(){
    ff(i,1,n) dis[i]=inf,vis[i]=0,mark[i]=0;//预处理
    while(!q.empty()) q.pop();//清空队列
    q.push(1);//将起点加入队列
    dis[1]=0,vis[1]=1,mark[1]++;
    while(!q.empty()){
        int u=q.front();//取出队首元素
        q.pop();
        vis[u]=0;//标记队首出队
        for(int i=head[u];i;i=a[i].nxt){//枚举u可到达的所有结点
            int v=a[i].to;
            if(dis[v]>dis[u]+a[i].w){//若以u为中转结点更优,更新
                dis[v]=dis[u]+a[i].w;
                if(!vis[v]){//若v不在队列,将其加入
                    vis[v]=1,mark[v]++;q.push(v);
                }
                if(mark[v]>=n) return 1;//判断负环,可由松弛原理推导
            }
        }
    }
    return 0;
}
int main(){
    int T=read(),u,v,w;
    while(T--){
        n=read(),m=read();
        tal=0;
        memset(head,0,sizeof(head));//初始化
        ff(i,1,m){
            u=read(),v=read(),w=read();
            add(u,v,w);
            if(w>=0) add(v,u,w);
        }
        if(spf()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 阿巴阿巴……

举报

相关推荐

0 条评论