一、Floyed:
弗洛伊德(Floyd)算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似,用于求每一对顶点的最短路径。
有向图无向图均可,也可以有负权边。
算法思想:
求任意两点之间的最短路径,两点之间可以直接到达但却不是最短的路径,要让任意两点(例如从顶点a点到顶点b)之间的路程变短,只能引入第三个点(顶点k),并通过这个顶点k中转即a->k->b,才可能缩短原来从顶点a点到顶点b的路程。那么这个中转的顶点k是1~n中的哪个点呢?甚至有时候不只通过一个点,而是经过两个点或者更多点中转会更短。
void floyd() { int i,j,k; for (k=1; k<=n; k++) for(i=1; i<=n; i++) for (j=1; j<=n; j++) Map[i][j]=min( Map[i][j],Map[i][k]+Map[k][j] ); }
Floyd优缺点分析
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
缺点:时间复杂度比较高(n3),不适合计算大量数据。
二、Dijkstra:
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他各个节点的最短路径。它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
适用于有向图和无向图,但不能有边权为负的情况。
算法思想:
通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。此外,引进两个集合S和U。集合S表示已求出最短路径的顶点(以及相应的最短路径长度),
而集合U则是表示还未确定最短路径的顶点(以及该顶点到起点s的距离)。
需要一个数组dis记录起点到各顶点的最短距离:
初始化,dis[s] = 0,其他dis[u] = INF
输入赋值,dis[v] = w,
初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是"起点s到该顶点的路径"。然后,从U中找出路径最短的顶点,并将其加入到S中;
接着,更新U中的顶点和顶点对应的路径(这是因为新加入的顶点只会影响与之直接相连的点)。然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 ... 重复该操作,直到遍历完所有顶点。
算法步骤:
a.初始时,S只包含起点,即S={v},起点v的距离为0。U包含除起点v外的其他顶点,即:U={其余顶点},若起点v与U中顶点u有边,即<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离起点v最小的顶点k,把k,加入S中(该选定的距离就是起点v到k的最短路径长度)。
c.以k为中间点,修改U中各顶点的距离;若从起点v-->k-->u的距离比原来距离v-->u短,则更新最短距离。
d.重复步骤b和c直到所有顶点都包含在S中。
//vis[i]标记已经处理过的点,dis[j]记录起点到点j最近的距离,way[][]表示路径关系 void Dijkstra(int s) { int mn; int n; for (int i = 1; i <= n; i++)//初始化 { vis[i] = 0; dis[i] = way[s][i]; } vis[s] = 1; for (int i = 1; i <= n; i++) { int u; mn = INF; u = -1; for (int j = 1; j <= n; j++)//找出离初始起点s直接距离最近的点,记录下标和最近距离 { if (vis[j] == 0 && dis[j] < mn) { u = j; mn = dis[j]; } } if (u == -1)//如果没有找到 break; vis[u] = 1; for (int j = 1; j <= n; j++)//更新 { if (vis[j] == 0) { if (dis[u] + way[u][j] < dis[j]) dis[j] = dis[u] + way[u][j]; } } } }
三、总结
Floyd算法与Dijkstra算法的不同
1.Floyd算法是求任意两点之间的距离,是多源最短路,而Dijkstra(迪杰斯特拉)算法是求一个顶点到其他所有顶点的最短路径,是单源最短路。
2.Floyd算法可以算带负权的,而Dijkstra(迪杰斯特拉)算法是不可以算带负权的。并且Floyd算法不能算负权回路(负权回路没有最短路)。
3.Dijkstra(迪杰斯特拉)算法时间复杂度一般是o(n^2),Floyd算法时间复杂度是o(n^3),Dijkstra(迪杰斯特拉)算法比Floyd算法块。
4.Floyd算法属于动态规划,Dijkstra(迪杰斯特拉)算法属于贪心算法。
负权回路: