题目大意:bellman-ford模板题
思路:以前是对着模板敲,时隔一年,自己温习了一边算法自己敲出来的,因为一个宏定义WA到想哭,至今没想清楚是什么意思.但终究是码出来了
算法核心思想就是:
第一重循环: 松弛n-1遍
第二重循环: 扫描所有的边,每次松弛一下入度结点
松弛了n-1遍之后,肯定能求得最短距离了
这时候如果再对所有的边再松弛一遍,如果还能够松弛话,则有负环
否则没有
O(n*m)的效率
AC Program:
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
typedef long long ll;
#define clr(a) memset((a),0,sizeof (a))
#define rep(i,a,b) for(int i=(a);i<(int)(b);i++)
#define per(i,a,b) for(int i=((a)-1);i>=(int)(b);i--)
#define inf 0x7ffffff
#define eps 1e-6
using namespace std;
int n,m,who;
int head[1510];
int dis[1510];
int cnt;//总边数
struct edge{
int from,to,w,next;
}e[5500];
void init(){
cnt=0;
int u,v,wei;
memset(e,0,sizeof(e));//初始化边数组
memset(head,-1,sizeof(head));//一开始初始化为0了,嚓
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&wei);
e[cnt].from=u;
e[cnt].to=v;
e[cnt].w=wei;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].from=v;
e[cnt].to=u;
e[cnt].w=wei;
e[cnt].next=head[v];
head[v]=cnt++;
}
for(int i=0;i<who;i++){
scanf("%d%d%d",&u,&v,&wei);
wei=-1*wei;
e[cnt].from=u;
e[cnt].to=v;
e[cnt].w=wei;
e[cnt].next=head[u];
head[u]=cnt++;
}
}
bool bellman_ford(){
//初始化相关数组?
//直接松弛?
for(int i=1;i<=n;i++){
dis[i]=inf;
}
dis[1]=0;
for(int i=0;i<n-1;i++){
for(int j=1;j<=n;j++){ //其实这里直接枚举所有的边也是可以的,不需要利用顶点来带出出边
//if(dis[j]==inf)continue; //小剪枝
for(int k=head[j];k!=-1;k=e[k].next){
int tt=e[k].to; //出边点
if(dis[tt]>dis[j]+e[k].w){//加e[k].w 小剪枝
dis[tt]=dis[j]+e[k].w;
}
}
}
}
for(int j=1;j<=n;j++){
//if(dis[j]==inf)continue;
for(int k=head[j];k!=-1;k=e[k].next){
int tt=e[k].to;
if(dis[tt]>dis[j]+e[k].w){//如果dis[tt]=inf,就说明没更新过,说明有可能是无法到达的点
//但有一点可以肯定,那就是没有松弛过,这样的点肯定不会存在于负环当中
return 1;//存在负环
}
}
}
return 0;//不存在负环
}
int main(){
int test;
cin>>test;
while(test--){
scanf("%d%d%d",&n,&m,&who);
//输入
//调用算法
init();
if(bellman_ford())
printf("YES\n");
else
printf("NO\n");
};
//system("pause");
return 0;
}