题目链接
题目大意
输入一个图,有N(1 ≤ N ≤ 500)个结点,M(1 ≤ M ≤ 2500)条正权无向边,W(1 ≤ W ≤ 200)条负权单向边,判断这个图中是否存在负权回路。
分析
判断图是否存在负环的模板题。
用Bellman-Ford算法,对所有边进行N-1轮松弛,如果之后还能继续进行松弛,则存在负权回路。时间复杂度O(N*(M+W))
代码
#include <iostream>
#include <cstdio>
using namespace std;
const int INF=99999999;
const int MAXM=5500;
const int MAXN=510;
struct Edge
{
int u,v,w;
}edge[MAXM];//边集数组
int dis[MAXN],n,m,t,edgenum;
void Add_Edge(int u,int v,int w)//构造边集数组
{
edgenum++;
edge[edgenum].u=u;
edge[edgenum].v=v;
edge[edgenum].w=w;
}
bool Bellmen_Ford()
{
for (int i=1;i<=n;i++)
dis[i]=INF;
dis[1]=0;
for (int k=1;k<=n-1;k++)//对所有边进行N-1轮松弛
{
bool flag=false;
for (int i=1;i<=edgenum;i++)
{
int u=edge[i].u;
int v=edge[i].v;
if (dis[v]>dis[u]+edge[i].w)
{
dis[v]=dis[u]+edge[i].w;
flag=true;
}
}
if (!flag) break;//如果松弛操作已经没有更新效果了,可提前退出循环
}
for (int i=1;i<=edgenum;i++)//如果N-1轮松弛后还能继续松弛,则存在负环
if (dis[edge[i].v]>dis[edge[i].u]+edge[i].w)
return true;
return false;
}
int main()
{
int F,i,u,v,w;
scanf("%d",&F);
while (F--)
{
scanf("%d%d%d",&n,&m,&t);
edgenum=0;
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
Add_Edge(u,v,w);
Add_Edge(v,u,w);
}
for (i=1;i<=t;i++)
{
scanf("%d%d%d",&u,&v,&w);
Add_Edge(u,v,-w);
}
bool ans=Bellmen_Ford();
if (ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}