Description
判断一个图中是否存在负环
Input
第一行为用例组数t,每组用例第一行为三个整数n,m,w分别表示顶点数,双向边个数,单向边个数,之后m行每行三个整数a,b,d表示a和之间有一条权值为d的双向边,最后w行每行三个整数a,b,d表示a和b之间有一条权值为-d的单向边
Output
若图中存在负环则输出YES,否则输出NO
Sample Input
2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8
Sample Output
NO
YES
Solution
SPFA判负环
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 11111
struct edge
{
int to,next;
int cost;
}g[maxn];
int head[maxn],tol;
int dis[maxn];//所有点到起点的最短距离
int cnt[maxn];//统计每个点的入队次数,若入队次数大于顶点数说明有负环
void init()//初始化
{
memset(head,-1,sizeof(head));
tol=0;
}
void add(int u,int v,int c)//单向边,从u到v,权值为c
{
g[tol].cost=c;
g[tol].to=v;
g[tol].next=head[u];
head[u]=tol++;
}
int spfa(int s,int n)//单源最短路,s是起点,n为点数
{
bool vis[maxn];
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
queue<int>que;
for(int i=1;i<=n;i++)dis[i]=INF;
cnt[s]++;
dis[s]=0;
vis[s]=true;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=g[i].next)
{
int v=g[i].to;
int c=g[i].cost;
if(dis[v]>dis[u]+c)
{
dis[v]=dis[u]+c;
if(!vis[v])
{
vis[v]=true;
que.push(v);
cnt[v]++;
if(cnt[v]>n)return 1;//存在负环
}
}
}
}
return 0;//不存在负环
}
int main()
{
int T,n,m,w;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&w);
init();
while(m--)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,c),add(v,u,c);
}
while(w--)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,-c);
}
printf("%s\n",spfa(1,n)?"YES":"NO");
}
}