题目大意: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; }