最短路径
1. 问题
用于计算一个节点到其他所有节点的最短路径。
2. 解析
Floyd:
1.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
把图用邻接矩阵dis表示出来,如果从Vi到Vj有路可达,则dis[i][j]=d,d表示该路的长度;否则dis[i][j]=无穷大。假设Vk是从Vi到Vj需要经过的点,把各个顶点插入图中,比较插点后的距离与原来的距离,dis[i][j] = min( dis[i][j], dis[i][k]+dis[k][j] ),如果dis[i][j]的值变小,则表明可以用Vk来更新Vi和Vj之间的距离。
Dijkstra:
从起始点开始,采用贪心的策略,每次遍历到距离始点距离最近且未被访问过的顶点的邻接节点,直到扩展到终点为止。
3. 设计
Floyd:
1 #include<stdio.h> 2 #include<string.h> 3 const int inf= 0x3f3f3f3f; 4 const int maxn= 100 + 10; 5 int dis[maxn][maxn]; 6 int n,m; //n表示顶点数量,m表示边的数量 7 //----------以下为floyd算法----------// 8 void floyd(){ 9 for(int k=1;k<=n;++k){ 10 for(int i=1;i<=n;++i){ 11 for(int j=1;j<=n;++j){ 12 if(dis[i][k]+dis[k][j]<dis[i][j]) 13 dis[i][j]=dis[i][k]+dis[k][j]; 14 } 15 } 16 } 17 } 18 //----------以上为floyd算法----------// 19 int main(){ 20 while(scanf("%d %d",&n,&m)!=EOF){ 21 memset(dis,inf,sizeof dis); //初始化,令各个点之间的距离为无穷大 22 for(int i=1;i<=m;++i){ 23 int x,y,z; 24 scanf("%d %d %d",&x,&y,&z); 25 dis[x][y]=z; //有向图 26 } 27 for(int i=1;i<=n;++i)dis[i][i]=0; 28 floyd(); 29 puts("以下为距离矩阵:"); 30 for(int i=1;i<=n;++i){ //输出距离矩阵 31 printf("%d: ",i); 32 for(int j=1;j<=n;++j){ 33 printf("%d%c",dis[i][j],j==n?' ':' '); 34 } 35 } 36 } 37 }
Dijkstra:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 1010; 6 const int inf = 0x3f3f3f3f; 7 int mp[maxn][maxn]; 8 int dis[maxn]; 9 bool vis[maxn]; 10 int n, m; //n表示顶点数量,m表示边的数量 11 //----------以下为dijkstra算法----------// 12 void dijkstra(int s) { //从s点出发,经过任意点 13 memset(vis, false, sizeof(vis)); 14 memset(dis, inf, sizeof(dis)); 15 vis[s] = 1; //判断该点是否被检查过 16 for (int i = 1; i <= n; i++){ 17 dis[i] = mp[s][i]; 18 } 19 dis[s] = 0; 20 for (int time = 1; time <= n - 1; time++){ //共n个数,检查次数n-1次// 21 int minn = inf; 22 int p = 1; 23 for (int i = 1; i <= n; i++){ //贪心 找出局部最优解 24 if (dis[i] < minn&&vis[i] != 1) { 25 minn = dis[i]; 26 p = i; 27 } 28 } 29 vis[p] = 1; //判断该点是否被检查过 30 for (int i = 1; i <= n; i++){ //用p点优化所有点 31 dis[i] = min(dis[i], dis[p] + mp[p][i]); //比较 32 } 33 } 34 } 35 //----------以上为dijkstra算法----------// 36 int main(){ 37 while(scanf("%d %d",&n,&m)!=EOF){ 38 memset(mp,inf,sizeof mp); //初始化,令各个点之间的距离为无穷大 39 for(int i=1;i<=m;++i){ 40 int x,y,z; 41 scanf("%d %d %d",&x,&y,&z); 42 mp[x][y]=z; //有向图 43 } 44 dijkstra(1); 45 printf("从1到n点的最短距离为:%d ",dis[n]); 46 } 47 }
4. 分析
//n为点的数量
flyod算法复杂度:O(n^3)
dijkstra算法复杂度:O(n^2)
5. 源码
Floyd: https://github.com/JayShao-Xie/algorithm-work/blob/master/floyd.cpp
Dijkstra: https://github.com/JayShao-Xie/algorithm-work/blob/master/dijkstra.cpp