[图的最短路径算法]Dijkstra, Bellman 您所在的位置:网站首页 最短路径算法dijkstra离散数学 [图的最短路径算法]Dijkstra, Bellman

[图的最短路径算法]Dijkstra, Bellman

2024-01-09 14:17| 来源: 网络整理| 查看: 265

随着算法教学进度的推进,虽然关于图论的专题只开了头,讲了$DFS$和$BFS$...

可是,万恶的计算机网络作业居然都是这样的题目,此处省略脏话1000+字,本真离散数学曾经学过的良心,默默温习一下~但是,与此同时也算是对算法的一点点预习吧~~~(你心态真好!!喂,刚刚搞完JAVA的大作业,然后就得知马上要交网络的作业啊喂!!!

正题开始

一. Dijkstra算法

中文维基百科译为"戴克斯特拉"。很遗憾,这种算法不能解决权值为负的情况,可是谁叫我们一般情况下权值都是正值呢?它的主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

下面又开始了无耻的转载了......

1. 算法思想

设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

2. 算法步骤

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则正常有权值,若u不是v的出边邻接点,则权值为∞。

b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

d.重复步骤b和c直到所有顶点都包含在S中。

3. 动画示例

动态演示Dijkstra

4. 代码实现

1 const int MAXINT = 32767; 2 const int MAXNUM = 10; 3 int dist[MAXNUM]; 4 int prev[MAXNUM]; 5 6 int A[MAXUNM][MAXNUM]; 7 8 void Dijkstra(int v0) 9 { 10   bool S[MAXNUM]; // 判断是否已存入该点到S集合中 11 int n=MAXNUM; 12   for(int i=1; iV; int E = graph->E; int dist[V]; // 第一步初始化 for (int i = 0; i < V; i++) dist[i] = INT_MAX; dist[src] = 0; // 第二步:松弛操作 for (int i = 1; i edge[j].src; int v = graph->edge[j].dest; int weight = graph->edge[j].weight; if (dist[u] + weight edge[i].src; int v = graph->edge[i].dest; int weight = graph->edge[i].weight; if (dist[u] + weight edge[0].src = 0; graph->edge[0].dest = 1; graph->edge[0].weight = -1; // add edge 0-2 (or A-C in above figure) graph->edge[1].src = 0; graph->edge[1].dest = 2; graph->edge[1].weight = 4; // add edge 1-2 (or B-C in above figure) graph->edge[2].src = 1; graph->edge[2].dest = 2; graph->edge[2].weight = 3; // add edge 1-3 (or B-D in above figure) graph->edge[3].src = 1; graph->edge[3].dest = 3; graph->edge[3].weight = 2; // add edge 1-4 (or A-E in above figure) graph->edge[4].src = 1; graph->edge[4].dest = 4; graph->edge[4].weight = 2; // add edge 3-2 (or D-C in above figure) graph->edge[5].src = 3; graph->edge[5].dest = 2; graph->edge[5].weight = 5; // add edge 3-1 (or D-B in above figure) graph->edge[6].src = 3; graph->edge[6].dest = 1; graph->edge[6].weight = 1; // add edge 4-3 (or E-D in above figure) graph->edge[7].src = 4; graph->edge[7].dest = 3; graph->edge[7].weight = -3; BellmanFord(graph, 0); return 0; }

 (Bellman-Ford算法转载自飘过的小牛博客:http://blog.csdn.net/niushuai666/article/details/6791765)

三、Floyd-Warshall算法

1. 算法简介

Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。 

2. 算法描述 

1)算法思想原理: 

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

      从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从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的最短路径的距离。 

2).算法描述: 

a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。    

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

3).Floyd算法过程矩阵的计算----十字交叉法 

方法:两条线,从左上角开始计算一直到右下角 如下所示

 给出矩阵,其中矩阵A是邻接矩阵,而矩阵Path记录u,v两点之间最短路径所必须经过的点 

$A_{-1}=\left[\begin{array}{cccc} 0 & 5 & \infty & 7  \\ \infty & 0 & 4 & 2 \\3 & 3 &0 & 2 \\\infty & \infty &1  & 0 \\\end{array}\right]$

$Path_{-1}=\left[\begin{array}{cccc}-1 & -1&-1 & -1  \\ -1& -1 & -1 & -1 \\-1 & -1 & -1 & -1 \\-1 & -1 &-1 & -1 \\\end{array}\right]$

相应计算方法如下: 

 

 

 

最后A3即为所求结果

3. 算法代码

这种算法的代码写起来超级简单啊~

1 typedef struct 2 { 3 char vertex[VertexNum]; //顶点表 4 int edges[VertexNum][VertexNum]; //邻接矩阵,可看做边表 5 int n,e; //图中当前的顶点数和边数 6 }MGraph; 7 8 void Floyd(MGraph g) 9 { 10   int A[MAXV][MAXV]; 11   int path[MAXV][MAXV]; 12   int i,j,k,n=g.n; 13   for(i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有