数据结构课设——校园导航系统第二天

弗洛伊德算法——求权值最短路线

(一)算法思想:

Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点 i 到点 j 的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)。

从任意节点 i 到任意节点 j 的最短路径不外乎2种可能,一是直接从i到j,二是从i经过若干个节点k到 j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

(二)算法过程

1)首先把初始化距离dist数组为图的邻接矩阵,路径数组path初始化为-1。其中对于邻接矩阵中的数首先初始化为正无穷,如果两个顶点存在边则初始化为权重   

2)对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是就更新它。

状态转移方程为

如果 dist[i][k]+dist[k][j] < dist[i][j]

则dist[i][j] = dist[i][k]+dist[k][j]

 

 

Dijikstra算法

 

Dijikstra算法主要是针对有权图的最短路径问题提出的,且具体问题中不能出现权值为负的边,即负值圈问题,

对于Dijikstra算法的理解,首先得从最短路径的最优子结构说起。(这部分引用海子的博客园的Dijkstra算法(单源最短路径)一文的说法)

 

最短路径的最优子结构性质

该性质描述为:如果P(i,j)={Vi…Vk…Vs…Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。

 

假设P(i,j)={Vi…Vk…Vs…Vj}是从顶点i到j的最短路径,则有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是从k到s的最短距离,那么必定存在另一条从k到s的最短路径P(k,s),那么P(i,j)=P(i,k)+P(k,s)+P(s,j)<P(i,j)。则与P(i,j)是从i到j的最短路径相矛盾。因此该性质得证。

 

那么Dijikstra算法描述如下:

假设存在G=<V,E>,源顶点为V0,U={V0},dist[i]记录V0到i的最短距离,path[i]记录从V0到i路径上的i前面的一个顶点。

1)从V-U中选择使dist[i]值最小的顶点i,将i加入到U中;

2)更新与i直接相邻顶点的dist值。dist[j]=min{dist[j],dist[i]+matrix[i][j]}

3)直到U=V,算法停止。

起始Dijikstra算法的本质就是贪心算法

 1 //14.查询两景点间的最短路径(floyd算法)
 2 void floyd(mgraph c)//一种暴力破解获取最短路径的算法 
 3 {    int i,j,k;
 4     for(i=1;i<=key;i++)//将图的邻接矩阵赋值给 shortest二维数组,将矩阵pathh全部初始化为-1 
 5     {    for(j=1;j<=key;j++)
 6         {    shortest[i][j]=c.arcs[i][j].adj;
 7             pathh[i][j]=j; 
 8         }
 9     }
10     /*int i1,j1,k1=0;
11     for(i1=1;i1<=key;i1++)
12         printf("%6d",i1);//横着的标号1到11
13     printf("\n");
14     for(i1=1;i1<=key;i1++)
15     {  printf("%d",i1);//竖着的标号1到11
16       for(j1=1;j1<=key;j1++)
17       {    
18          printf("%6d",pathh[i1][j1]);
19           k1++;
20           if(k1%key==0) printf("\n");
21       }        
22     }
23     printf("\n\n\n");*/ 
24     
25     for(k=1;k<=key;k++)//核心操作,完成了以k为中间点对所有的顶点对(i,j)进行检测和修改 
26     {    for(i=1;i<=key;i++)
27         {    for(j=1;j<=key;j++)
28              {
29                  if(shortest[i][j]>shortest[i][k]+shortest[k][j])
30                  {    shortest[i][j]=shortest[i][k]+shortest[k][j];                     
31                       pathh[i][j]=pathh[i][k];//记录一下所走的路 //P数组用来存放前驱顶点  
32                 }
33              }
34         }
35     }
36 }
37 /*void printf_Pshuzu() //输出前驱矩阵
38 {    int i,j,k=0;
39     for(i=1;i<=key;i++)
40         printf("%6d",i);//横着的标号0到11
41     printf("\n");
42     for(i=1;i<=key;i++)
43     {  printf("%d",i);//竖着的标号0到11
44       for(j=1;j<=key;j++)
45       {    printf("%6d",pathh[i][j]);
46           k++;
47           if(k%key==0) printf("\n");
48       }        
49     }
50     printf("\n\n\n");
51 }*/

 

 1 //打印出最短路径
 2 void display(mgraph c, int i, int j)
 3 {
 4     int a, b;
 5     a = i;
 6     b = j;
 7     printf("您要查询的两景点间最短路径:\n\n");
 8     printf("%d%s", a, c.vexs[a].name);
 9     while (pathh[i][j] != b)
10     {
11         printf("-->%d%s", pathh[i][j], c.vexs[pathh[i][j]].name);
12         i = pathh[i][j];
13     }
14     printf("-->%d%s\n\n", b, c.vexs[b].name);
15     printf("%s-->%s的最短路径是:%d 米。\n\n", c.vexs[a].name, c.vexs[b].name, shortest[a][b]);
16 }
17 //任意两点间最短距离(弗洛伊德算法)
18 int shortdistance(mgraph c)
19 {
20     int i, j;
21     printf("请输入要查询的两个景点的数字编号(1->11)中间用空格间隔开。\n");
22     scanf("%d %d", &i, &j);
23     if (i > key || i < 0 || j > key || j < 0)
24     {
25         printf("输入信息错误!\n\n");
26         printf("请输入要查询的两个景点的数字编号(1->11)中间用空格间隔开。\n");
27         scanf("%d %d", &i, &j);
28     }
29     else
30     {
31         floyd(c); //printf_Pshuzu();
32         display(c, i, j);
33     }
34     return 1;
35 }
 1 //用迪杰斯特拉算法,求出一个景点到其他景点间的最短路径,
 2 void shortestpath_dij(mgraph c)
 3 {
 4     int v0, v, w, k = 1, min, t, p;
 5     int final[MaxVertexNum];          //final[w]=1表示已经求得顶点V0到Vw的最短路径
 6     int Patharc[MaxVertexNum];        //用于存储最短路径下标的数组
 7     int ShortPathtable[MaxVertexNum]; //用于存储到各点最短路径的权值和
 8     printf("\n请输入一个起始景点的编号:");
 9     scanf("%d", &v0);
10     printf("\n\n");
11     while (v0 < 0 || v0 > key)
12     {
13         printf("\n您输入的景点编号不存在\n");
14         printf("请重新输入:");
15         scanf("%d", &v0);
16     }
17     //初始化数据
18     for (v = 1; v <= c.vexnum; v++) //数组0还是空出来
19     {
20         final[v] = 0;                          //全部顶点初始化为未找到最短路径
21         ShortPathtable[v] = c.arcs[v0][v].adj; //将与v0点有连线的顶点加上权值
22         Patharc[v] = 0;                        //初始化路径数组p为0
23     }
24     ShortPathtable[v0] = 0; // V0至v0的路径为0
25     final[v0] = 1;          //V0至v0不需要路径
26     //开始主循环,每次求得V0到某个v顶点的 最短路径
27     for (v = 1; v <= c.vexnum; v++)
28     {
29         min = Infinity;
30         for (w = 1; w <= c.vexnum; w++) //找出最近的顶点和权值
31         {
32             if (!final[w] && ShortPathtable[w] < min) //有边
33             {
34                 k = w;
35                 min = ShortPathtable[w];
36             }
37         }
38         final[k] = 1; //将目前找到的最近的顶点置1
39                       //修正当前最短路径及距离
40         for (w = 1; w <= c.vexnum; w++)
41         { //如果经过v顶点的路径比现在这条路径的长度短的话,更新
42             if (!final[w] && (min + c.arcs[k][w].adj < ShortPathtable[w]))
43             {
44                 ShortPathtable[w] = min + c.arcs[k][w].adj; //修改当前路径长度
45                 Patharc[w] = k;                             //存放前驱结点(像糖葫芦)
46             }
47         }
48     }
49 
50     /*//打印P数组
51      printf("打印P数组:");
52      for(t=1;t<=c.vexnum;t++)
53      {
54          printf("%d ",Patharc[t]);
55      }
56      printf("\n\n");
57      //打印s数组
58      printf("打印S数组:");
59      for(t=1;t<=c.vexnum;t++)
60      {
61          printf("%d ",ShortPathtable[t]);
62      }
63      printf("\n\n");*/
64 
65     //打印最短路径
66     for (t = 1; t <= c.vexnum; t++)
67     {
68         p = t;
69         if (t != v0) //反向输出
70         {
71             printf("%d%s", t, c.vexs[t].name);
72             for (w = 1; w <= c.vexnum; w++)
73             {
74                 if (Patharc[p] != 0)
75                 {
76                     printf("<--%d%s", Patharc[p], c.vexs[p].name);
77                     p = Patharc[p];
78                 }
79             }
80             printf("<--%d%s", v0, c.vexs[v0].name);
81             printf("\n总路线长为%d米\n\n", ShortPathtable[t]);
82         }
83     }
84 }

 

posted @ 2021-12-29 20:55  取鱼  阅读(209)  评论(0)    收藏  举报