首先需要明确的是,如果一个图里面有负环,那么用spfa算法时,存在一个点放进队列的次数超过n。可以这样想,既然为负,那么每放进一次,结果就变小,再放进去,再小,所以一直这样下去,有点高中生物中的正反馈的意味…
其他的就是spfa算法了。
详见代码:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年09月09日 星期日 18时08分28秒
> Description:POJ3259,spfa算法
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define N 1000
struct node
{
int to;
int val;
int nex;
}E[50000];//边
int head[N];
bool vis[N];//该点是否被放进队列中
int dis[N];
int used[N];//被放进队列的次数,大于n,则存在负环
int t,n,m1,m2;
int cnt;
void addEdge(int a, int b, int val)
{
E[cnt].val=val;
E[cnt].to=b;
E[cnt].nex=head[a];
head[a]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
for (int i=0; i<n; i++)
dis[i]=111111;
scanf("%d%d%d",&n,&m1,&m2);
for (int i=0; i<m1; i++)
{
int a,b,val;
scanf("%d%d%d",&a,&b,&val);
addEdge(a-1,b-1,val);
addEdge(b-1,a-1,val);
}
for (int i=0; i<m2; i++)
{
int a,b,val;
scanf("%d%d%d",&a,&b,&val);
addEdge(a-1,b-1,-val);
}
}
bool spfa(int s)
{
dis[s]=0;
memset(vis,false,sizeof(vis));
memset(used,0,sizeof(used));
queue<int>q;
q.push(s);
while (!q.empty())
{
int cur=q.front();
q.pop();
if (used[cur]>n)
return true;
int k=head[cur];
vis[cur]=false;
while (k != -1)
{
if (dis[E[k].to]>dis[cur]+E[k].val)
{
dis[E[k].to]=dis[cur]+E[k].val;
if (!vis[E[k].to])
{
q.push(E[k].to);
used[E[k].to]++;
vis[E[k].to]=true;
}
}
k=E[k].nex;
}
}
return false;
}
int main()
{
while (~scanf("%d",&t))
{
while (t--)
{
init();
int i;
for ( i=0; i<n; i++)
{
if (spfa(i))
{
printf("YES\n");
break;
}
}
if (i>=n)
printf("NO\n");
}
}
return 0;
}