1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 #define MAX 9999999 7 8 using namespace std; 9 10 struct node 11 { 12 int u, v, w;//u 为起点,v为终点,w为u—>v的权值 13 }; 14 node edge[5203]; 15 int n, m;//n 点数 m 边数 16 17 bool bellman_ford() 18 { 19 int i, j; 20 bool flag; 21 int dis[503];//保存最短路径 22 23 fill(dis,dis+n,MAX);//初始化 24 dis[1] = 0;//因为判断是否有负环,对整个图而言,So s = 1; 25 // 26 for(i=1;i<n;i++)//共需进行|V|-1次 27 { 28 flag = false;//优化 初始化为假 29 for(j=0;j<m;j++)//对每一条边 30 { 31 // if u.d>v.d+w(u,v) , u.d = v.d+w(u,v); 32 if(dis[edge[j].u]>dis[edge[j].v]+edge[j].w){//进行松弛 33 dis[edge[j].u] = dis[edge[j].v]+edge[j].w;//松弛操作成功 34 flag = true;//松弛成功变为真 35 } 36 } 37 if(!flag)//若每条边没有松弛 38 break;//跳出循环 39 } 40 // 41 for(i=0;i<m;i++) 42 if(dis[edge[i].u]>dis[edge[i].v]+edge[i].w)//进行|V|-1次操作后 有边还能进行松弛 说明 43 return true;//存在负环 44 return false;//不存在负环 45 } 46 47 int main() 48 { 49 int t, k, i; 50 51 scanf("%d",&t);//输入测试数据的组数 52 while(t-- && scanf("%d %d %d",&n,&m,&k)){//输入点数,正边数,负边数 53 for(i=0;i<m;i++) 54 { 55 scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);//输入u,v,w; 56 edge[i+m].u = edge[i].v;//双向 57 edge[i+m].v = edge[i].u;//双向 58 edge[i+m].w = edge[i].w;//双向 59 } 60 m <<= 1;//正边为双向 所以m = m*2; 61 for(i=m;i<m+k;i++) 62 { 63 scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);//存负边数(单向) 64 edge[i].w = -edge[i].w;//负边就要是负的 65 } 66 m += k;//单向,So不需要*2 67 printf("%s ",bellman_ford()?"YES":"NO");//输出结果 68 } 69 return 0; 70 }
题目大意: 第一行 输入一个数 是表示几组测试数据
第二行 三个数 N(点的个数),M(正边的个数),W(负边的个数) 注意 :正边为双向的,负边为单向的。
然后 M行u,v,w;
再然后W行u,v,w;
求这个图是不是存在负环。 有 YES 没NO。
若没有负环外循环最多进行|V|-1次即可,就可得到最短路径,那么若存在负环,则第|V|次操作还改变D数组,则有负环。
负环即回路中权值相加为负数。 如果陷入负环中,环中的顶点最短路径就会陷入死循环,无限变小,不会停下。。。
这题废物了我两天,不过也值了。O(∩_∩)O~。。