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