P3385 【模板】负环
题目链接
这道题就是一个SPFA纯板子题,但是前提是要理解SPFA的工作原理,SPFA与Dijkstra还是有很大不同,SPFA用的是队列,而Dijkstra用的是优先队列;还有两者对点的标记,也是不相同的,SPFA要对一个点进行最多n-1次的判断,而Dijkstra只需一次。因为Dijkstra用的是贪心加优先队列,每次第一个出来的必定是最短的,而SPFA不是。这道题的坑点还是挺多的;
1.YE5不是YES,N0不是NO;
2.数组尽量开大点;不然容易RE;
代码:
#include<bits/stdc++.h>
using namespace std;
struct Node{
int to,next,w;
}edge[60010];
int cnt;
int t,n,m;
int head[20010];
int dis[20010];
int vis[20010];
int sum[20010];//统计次数的数组
void add(int p,int q,int w){
edge[cnt].to=q;
edge[cnt].next=head[p];
edge[cnt].w=w;
head[p]=cnt++;
}
queue<int>qu;
bool SPFA(){
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(sum,0,sizeof(sum));
dis[1]=0;
qu.push(1);
vis[1]=1;
while(!qu.empty()){
int k=qu.front();
qu.pop();
vis[k]=0;
sum[k]++;
if(sum[k]>=n){//含有负环
return false;
}
for(int i=head[k];~i;i=edge[i].next){
int u=edge[i].to;
if(dis[u]>dis[k]+edge[i].w){
dis[u]=dis[k]+edge[i].w;
if(!vis[u]){
vis[u]=1;
qu.push(u);
}
}
}
}
return true;
}
int main(){
scanf("%d",&t);
while(t--){
memset(head,-1,sizeof(head));
for(int i=1;i<=6000;i++){
edge[i].next=0;edge[i].to=0;edge[i].w=0;
}
scanf("%d%d",&n,&m);
int p,q,w;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&p,&q,&w);
if(w>=0){
add(p,q,w);
add(q,p,w);
}
else{
add(p,q,w);
}
}
if(SPFA()){
printf("N0\n");
}
else{
printf("YE5\n");
}
while(!qu.empty()){
qu.pop();
}
}
return 0;
}