Floyd+Dijkstra最短路径 源码解析

最短路径

A.Floyd算法

核心思想:
建立两个二维数组,
D[v][w]=m:
顶点v到顶点w的最短路径权值为m。
代表顶点到顶点的最短路径权值和的矩阵。
P[v][w]=k:
顶点v和w之间的中转路径k,即v先到k顶点再到w顶点的路径最短。
代表对应顶点的最短路径的前驱矩阵,用来储存路径。

D^i[v][w]=min(D^{i-1}[v][w],D^{i-1}[v][k]+D^{i-1}[k][w])

if(D^i[v][w]==D^{i-1}[v][w])P[v][w]=w;

if(D^i[v][w]==D^{i-1}[v][k]+D^{i-1}[k][w])P[v][w]=P[v][k];

步骤:
1.创建D[][],P[][]数组。
2.初始化D,P:
   a D[v][w]的初始权值即v与w间边的原有权值G.arc[v][w];
   b P[v][w]的初始路径即w
3.循环k,找到最佳中转点。
4.循环v,循环w,遍历矩阵的每条边。
5.如果满足经过顶点k的中转能使路径更短,
  则更新D[v][w]=D[v][k]+D[k][w].
       P[v][w]=P[v][k];
typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];
void shortestPath_Floyd(MGraph G,Patharc *P,ShortPathTable *D)
{
     int v,w,k;
     for(v=0;v<G->numNodes;v++)
     {
          for(w=0;w<G->numNodes;w++)
          {
               (*D)[v][w]=G.arc[v][w];
               (*P)[v][w]=w;
          }
     }
     for(k=0;k<G->numNodes;k++)
     {
          for(v=0;v<G->numNodes;v++)
          {
               for(w=0;w<G->numNodes;w++)
               {
                    if((*D)[v][w]>(*D)[v][k]+(*D)[k][w])
                    {
                         (*D)[v][w]=(*D)[v][k]+(*D)[k][w];
                         (*P)[v][w]=(*P)[]
                    }
               }
          }
     }
}

B.Dijkstra

#include<stdio.h>
#include<malloc.h>
#include<math.h>
#include<string.h>
​
typedef char VerexType;
typedef int EdgeType;
#define MAXVEX 100
#define INFINITY 65535
​
typedef struct 
{
     VerexType vexs[MAXVEX];//储存顶点信息:ves[顶点序号]=顶点值
     EdgeType arc[MAXVEX][MAXVEX];//储存边的权值信息:arc[顶点1][顶点2]=顶点1与顶点2间边的权值
     int numNodes, numEdges;//顶点数和边数
}MGraph, * pMGraph;
typedef int Patharc[MAXVEX];//储存最短路径下标数组
typedef int ShortPathTable[MAXVEX];//储存到各点最短路径权值和
​
void CreateMGraph(pMGraph G) 
{
     int i, j, k, w;
     printf("输入顶点数和边数(逗号断开):\n");
     scanf("%d,%d", &G->numNodes, &G->numEdges);
     getchar();
     printf("输入顶点信息:\n");
     for (i = 0; i < G->numNodes; i++) {
          printf("顶点%d信息:\n", i);
          scanf("%c", &G->vexs[i]);
          getchar();
     }
     for (i = 0; i < G->numNodes; i++)
          for (j = 0; j < G->numNodes; j++)
               G->arc[i][j] = INFINITY;
     for (k = 0; k < G->numEdges; k++) {
          printf("输入第%d条边(vi,vj)的下标i,下标j和权w(逗号断开):\n", k + 1);
          scanf("%d,%d,%d", &i, &j, &w);
          G->arc[i][j] = w;
          G->arc[j][i] = w;
     }
}
​
//Dijkstra,求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度D[v]
//P[v]=v的前驱顶点下标(前驱即最短路径是经过哪个顶点实现的),D[v]=v0~v的最短路径长度和
void ShortestPath_Dijkstra(MGraph G, int v0, Patharc* P, ShortPathTable* D) {
     int v, w, k, min;
     int final[MAXVEX];//final[w]=1表示已经求得v0~vw的最短路径
     //初始化数据
     for (v = 0; v < G.numNodes; v++)
     {
          final[v] = 0;//全部顶点初始化为未知路径状态
          (*D)[v] = G.arc[v0][v];//将与v0有连线的顶点加上权值
          (*P)[v] = -1;//初始化路径数组
     }
     (*D)[v0] = 0;//v0到v0路径为0
     final[v0] = 1;//v0到v0不需要求路径
     //主循环,每次求得v0到v的最短路径
     for (v = 1; v < G.numNodes; v++) 
     {
          min = INFINITY;//min:当前已知离v的最短路径
          //找离v0相连的顶点
          for (w = 0; w < G.numNodes; w++) 
          {
               if (!final[w] && (*D)[w] < min) //经过w顶点更近
               {
                    k = w;
                    min = (*D)[w];
               }
          }
          final[k] = 1;//将目前找到的最近顶点至为1
          //更新当前最短路径及距离
          for (w = 0; w < G.numNodes; w++) 
          {
               //如果经过k顶点的路径比当前短
               if (!final[w] && (min + G.arc[k][w] < (*D)[w])) 
               {
                    (*D)[w] = min + G.arc[k][w];//修改路径长度
                    (*P)[w] = k;//修改当前路径
               }
          }
     }
}
int main() {
     MGraph G;
     int v0;
     Patharc P;
     ShortPathTable D;
     int i, j;
     CreateMGraph(&G);
     printf("输入起始顶点序号:\n");
     scanf("%d", &v0);
     ShortestPath_Dijkstra(G, v0, &P, &D);
     for (i = 0; i < G.numNodes; i++) {
          if (i != v0 && D[i] != INFINITY) {
               printf("%c->%c最短路径长度: %d\n", G.vexs[i], G.vexs[v0], D[i]);
               printf("最短路径:");
               j = i;
               printf("%c", G.vexs[i]);
               while (P[j] != -1) {
                    printf("->%c", G.vexs[P[j]]);
                    j = P[j];
               }
               printf("->%c\n", G.vexs[v0]);
          }
     }
     return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值