s负环:环的权值和小于等于0
判断条件:最短路边数绝对不可能大于等于n!!!
在松弛操作的时候,用一个cnt数组记录最短路边数,如果大于等于0那么一定存在负环,就是因为负环才一直迭代下去,导致最短路长度大于等于n
这道题,出发点任意,那么只要找到一个负环,肯定可以穿越回出发点之前的某一时刻,也就是在负环上作为出发点即可。
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ll long long
#define x first
#define y second
typedef pair<int,int> PII;
const int N=500+10,M=2700+10;
int n,m,k,ans,ecnt;
int head[N],vis[N],d[N],cnt[N];
struct edge {
int u,v,w,next;
} E[M<<1];
void add(int u,int v,int w) {
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].next=head[u];
head[u]=ecnt;
}
bool spfa() {
memset(vis,0,sizeof vis);
memset(d,0,sizeof d);//负环问题初始值无所谓
memset(cnt,0,sizeof cnt);
queue<int> q;
for(int i=1; i<=n; i++) { //超级源点,spfa一次,结果就是全部入队
q.push(i);
vis[i]=1;
}
while(!q.empty()) {
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u]; i; i=E[i].next) {
int v=E[i].v;
if(d[v]>d[u]+E[i].w) {
d[v]=d[u]+E[i].w;
cnt[v]=cnt[u]+1;//统计最短路边数
if(cnt[v]>=n)return true;//最短路边数大于等于n,一定存在负环
if(!vis[v]) {
vis[v]=1;
q.push(v);
}
}
}
}
return false;
}
int main() {
int T;
cin>>T;
while(T--) {
cin>>n>>m>>k;
ecnt=0;
memset(head,0,sizeof head);
for(int i=1; i<=m; i++) {
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
for(int i=1; i<=k; i++) {
int u,v,w;
cin>>u>>v>>w;
add(u,v,-w);
}
if(spfa())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}