zbyQIN

 

A*,spfa,和如何利用spfa判断负环

A*即是在dij的思路上加上预估函数

注意:此处的欧式距离即为max(|x1-x2|,|y1-y2|);

   spfa算法

  每个点至多被松弛n-1次;

  我们利用队列来记录哪些点被松弛过(因为被松弛过说明距离变的更小,就有机会更新别人),一个点一旦出队,即取消标记

 

  那么我们又该如何判断负环呢?

  我们有一种最为稳定的办法(不会被某些特殊数据hack掉)

  即维护一个入队次数的数组,注意是入队次数,只有能被松弛且不在队列中才有机会入队。

  如果一个点的入队次数大于n-1说明一定存在负环。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=100005;

int t,n,m; 
int head[N],nxt[N],to[N],cnt,val[N];

queue<int>q;

int num[N],dis[N],vis[N];

void add(int x,int y,int z)
{
    cnt++;
    nxt[cnt]=head[x];
    head[x]=cnt;
    to[cnt]=y;
    val[cnt]=z;
}


bool spfa()
{
        q.push(1);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            vis[x]=0;
            
            for(int i=head[x];i;i=nxt[i])
            {
                int y=to[i];
                if(dis[y]>dis[x]+val[i])
                {
                    dis[y]=dis[x]+val[i];
                    
                    
                    if(!vis[y])
                    {
                        if(++num[y]>=n)return 0;
                        vis[y]=1;
                        q.push(y);
                    }
                }
            }
        }
        return 1;
}
signed main()
{
    
    cin>>t;
    while(t--)
    {
        
        cin>>n>>m;
        for(int i=1;i<=n;i++)dis[i]=1e9;
        memset(num,0,sizeof(num));
        memset(vis,0,sizeof(vis));
        memset(head,0,sizeof(head));
        while(!q.empty())q.pop();
        cnt=0;
        dis[1]=0;
        num[1]=1;
        vis[1]=1;
        for(int i=1,u,v,w;i<=m;i++)
        {
            cin>>u>>v>>w;
            if(w>=0)
            {
                add(u,v,w);
                add(v,u,w);
            }
            else add(u,v,w);
        }
        
        if(spfa())cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    
    
    
    
    return 0;
}

 

 

posted on 2024-10-20 22:27  秦風  阅读(3)  评论(0编辑  收藏  举报

导航