算法复习:最短路Dijkstra - Ford - Floyd
Dijkstra算法适用范围是单源最短路,有向图或者无向图,不能处理负权值
Floyd算法适用多源最短路,有向图或者无向图,可以处理负权值但是不能处理负权回路
Ford 算法单源最短路,可以处理负权值,能检测负权回路
Leetcode 743. 网络延迟时间
一、先用Dijkstra算法解,输入是vector要转存一下,另外找的是最后一个传播到的节点所用时间
#define max 999999 #define CLR(donser,value) memset(donser,value,sizeof(donser)) class Solution { public: int networkDelayTime(vector<vector<int>>& times, int N, int K) { int dis[N+1],map[N+1][N+1]; CLR(dis,max); bool visit[N+1]; CLR (visit,false); for(int i=1;i<=N;i++)//先初始化map for(int j=1;j<=N;j++) map[i][j]=max; for(int i=0;i<times.size();i++)//把边转存到map map[times[i][0]][times[i][1]]=times[i][2]; for(int i=1;i<=N;i++)//和起点直接相连的边 { if(i==K) dis[i]=0; else dis[i]=map[K][i]; } visit[K]=true;//起点做标记 for(int i=1;i<=N;i++)//循环N次 { int min=max,k; for(int j=1;j<=N;j++)//找未加入visit的点所连最小边 { if(!visit[j]&&min>dis[j]) min=dis[k=j];//k记录取到最小值时的下标 } if(min==max)//不存在没加入的边了 break; visit[k]=true; for(int j=1;j<=N;j++)//给没有加入的边更新权值 { if(!visit[j]&&dis[j]>dis[k]+map[k][j])//新加入了K,把与K相连的边加入 dis[j]=dis[k]+map[k][j]; } } int find=0; for(int i=1;i<=N;i++) if(dis[i]>find) find=dis[i]; if(find==max) return -1; else return find; } };
另外,Dijkstra算法模板:
#define N 101 #define max 999999 #define CLR(arr,what) memset(arr,what,sizeof(arr)) int nodenum,edgenum; int map[N][N],dis[N]; bool visit[N]; int Dijkstra(int src,int des)//输入开始点和结束点 { int temp,k; CLR(visit,false); for(int i=0;i<=nodenum;i++)//先把和开始点直接相连的边找出来 { if(i==src) dis[i]=0;//dis[i]存连入i的边,起始点赋0 else dis[i]=map[src][i]; } visit[src]=true;//起始点做标记 dis[src]=0; for(int i=1;i<=nodenum;i++)//做i次循环 { temp=max; for(int j=1;j<=nodenum;j++)//寻找没有加入visit的节点中权值最小的 { if(!visit[j]&&temp>dis[j]) temp=dis[k=j]; } if(temp==max)//不存在没有加入的边时结束 break; visit[k]=true;//访问标记 for(int j=1;j<=nodenum;j++)//加入k点以后更新和k相连的边 { if(!visit[j]&&dis[j]>dis[k]+map[k][j]) dis[j]=dis[k]+map[k][j]; } } return dis[des]; }
Leetcode 743. 网络延迟时间
二、改用Floyd算法解决,floyd三层循环更新二维表,本质上就是借助一个中间点实现节点更新,时间复杂度:O(N^3)。
#define max 999999 class Solution { public: int networkDelayTime(vector<vector<int>>& times, int N, int K) { int map[N+1][N+1]; for(int i=1;i<=N;i++)//先初始化map 对角线0,其他max for(int j=1;j<=N;j++) map[i][j]=(i==j?0:max); for(int i=0;i<times.size();i++)//把边转存到map map[times[i][0]][times[i][1]]=times[i][2]; for(int k=1;k<=N;k++) { int lable=0; for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) if(map[i][k]<max&&map[k][j]<max&&map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j]; } int find=0; for(int i=1;i<=N;i++) { if(map[K][i]>find) find=map[K][i]; } if(find==max) return -1; else return find; } };
Floyd核心代码:
for(int k=1;k<=N;k++) for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) if(map[i][k]<max&&map[k][j]<max&&map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j];
Leetcode 743. 网络延迟时间
三、改用Bellman-Ford算法,最外层循环节点数-1次,内层循环遍历所有的边值更新权值表,时间复杂度O(NM)
l#define max 999999 #define CLR(donser,value) memset(donser,value,sizeof(donser)) class Solution { public: int networkDelayTime(vector<vector<int>>& times, int N, int K) { int dis[N+1]; CLR(dis,max); dis[K]=0; for(int k=1;k<=N-1;k++)//第一个点是确定的,循环次数-1 { for(int i=0;i<times.size();i++)//遍历所有边 { if(dis[times[i][0]]<max&×[i][2]<max&&dis[times[i][0]]+times[i][2]<dis[times[i][1]]) dis[times[i][1]]=dis[times[i][0]]+times[i][2]; } } int find=0; for(int i=1;i<=N;i++) if(dis[i]>find) find=dis[i]; if(find>=max) return -1; else return find; } };
Ford核心代码:
for(int k = 1; k <= n-1; k++) //进行n-1轮松弛 for(int i = 1; i <= m; i++) //枚举每一条边 if(dis[u[i]] != INF && w[i] != INF && dis[u[i]] + w[i] < dis[v[i]]) //尝试对每一条边进行松弛 dis[v[i]] = dis[u[i]] + w[i];