分析
写的时候一眼出做法,SPFA判断负环问题。
其实很多题解都说只需要从1出发判断走过的路径数量就能判负环,但是我觉得不太对,万一不连通咋办,如果1是一个孤点,但是其他地方有环呢?所以我就对每一个点为起点做一次SPFA,判断能否回到这个点,这样子也不用统计经过多少个边了,直接判断走回这个点的时候路径长度是否为负就行。其实还可以优化的就是对于每个连通块做一次。
时间复杂度 O ( t n k m ) ( k 为常数 ) O(tnkm)(k为常数) O(tnkm)(k为常数)
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
struct node
{
int to,next,w;
}e[10010];
int t;
int n,m,k,dis[1010],v[1010];
int hd[10010],tot;
void add(int x,int y,int w)
{
e[++tot]=(node){y,hd[x],w};
hd[x]=tot;
}
int spfa(int s)
{
queue<int> q;
memset(dis,0x3f,sizeof(dis));
memset(v,0,sizeof(v));
dis[s]=0;
q.push(s);
v[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
v[x]=0;
for(int i=hd[x];i;i=e[i].next)
{
if(dis[x]+e[i].w<dis[e[i].to])
{
dis[e[i].to]=dis[x]+e[i].w;
if(dis[e[i].to]<0&&e[i].to==s) return 1;
if(!v[e[i].to])
{
q.push(e[i].to);
v[e[i].to]=1;
}
}
}
}
return 0;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
cin>>t;
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
for(int i=1;i<=k;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,-w);
}
int ff=0;
for(int i=1;i<=n;i++)
{
if(spfa(i))
{
cout<<"YES"<<endl;
ff=1;
break;
}
}
if(ff==0) cout<<"NO"<<endl;
memset(hd,0,sizeof(hd));
tot=0;
}
return 0;
}