在一个无权的图中,若从一个顶点到另一个顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。由于从一个顶点到另一个顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,把路径长度最短(即经过的边数最少)的那条路径叫作最短路径或者最短距离。
对于带权的图,考虑路径上各边的权值,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或带权路径长度。从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或最短距离。
Floyd算法
全称为Floyd—Warshall。算法用于求所有点对的最短距离。其时间复杂度为O(n^3)
这是一个dp的过程
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j])
即从顶点i到j且经过顶点k的最短路径长度。
代码实现:
void floyd()
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
Dijkstra算法
简单描述
Dijkstra算法是有荷兰计算机科学家Edsger Wybe Dijkstra提出。该算法常用于路由算法或者作为其他图算法的一个子模块。举例来说,如果图中的顶点表示城市,而边上的权值表示城市间的距离,那么该算法可以用来计算;两个城市之间的最短路径。
Dijkstra单源最短路算法,即计算从起点出发到每个点的最短路。Dijkstra常常作为其他算法的预处理。
使用邻接矩阵的时间复杂度为O(n^2)
Dijkstra算法的思想
每次选择已经访问过(标记为true)的最短边的点,并用这个点进行更新,更新的内容为未访问的点到源点的最短路径。(更新的过程:当该点到源点的距离加上到未访问的点的距离小于未访问过点到源点的距离的时候,对未访问过的点的距离进行更新)。
举一个例子来说明算法的过程
定义源点为0,dis[i]
为源点0到顶点的最短路径。
其过程描述如下:
第1步:从源点0开始,找到与其邻接的点:1,2,3,更新
dist[]
数组,因0不与4邻接,故dist[4]
为正无穷。在dist[]
中找到最小值,其顶点为2,即此时已找到0到2的最短路。第2步:从2开始,继续更新
dist[]
数组:2与1不邻接,不更新;2与3邻接,因0→2→3
比dist[3]
大,故不更新dist[3]
;2与4邻接,因0→2→4
比dist[4]
小,故更新dist[4]
为4。在dist[]
中找到最小值,其顶点为3,即此时又找到0到3的最短路。第3步:从3开始,继续更新
dist[]
数组:3与1邻接,因0→3→1
比dist[1]
小,更新dist[1]
为5;3与4邻接,因0→3→4
比dist[4]
大,故不更新。在dist[]
中找到最小值,其顶点为4,即此时又找到0到4的最短路。第4步:从4开始,继续更新
dist[]
数组:4与1不邻接,不更新。在dist[]
中找到最小值,其顶点为1,即此时又找到0到1的最短路。第5步:所有点都已找到,停止。
代码实现
#include<iostream>
#include <string.h>
using namespace std;
int matrix[100][100]; ///邻接矩阵
bool visited[100]; ///标记数组
int dist[100]; ///源点到顶点i的最短距离
int path[100]; ///记录最短路的路径
int source; ///源点
int vertex_num; ///顶点数
int arc_num; ///弧数
void Dijkstra(int source)
{
memset(visited, 0, sizeof(visited)); ///初始化标记数组
visited[source] = true;
for (int i = 0; i < vertex_num; i++)
{
dist[i] = matrix[source][i];
path[i] = source;
}
int min_cost; ///权值最小
int min_cost_index; ///权值最小的下标
for (int i = 1; i < vertex_num; i++) ///找到源点到另外vertex_num-1个点的最短路径
{
min_cost = INT_MAX;
for (int j = 0; j < vertex_num; j++)
{
if (visited[j] == false && dist[j] < min_cost) ///找到权值最小
{
min_cost = dist[j];
min_cost_index = j;
}
}
visited[min_cost_index] = true; ///该点已找到,进行标记
for (int j = 0; j < vertex_num; j++) ///更新dist数组
{
if (visited[j] == false &&
matrix[min_cost_index][j] != INT_MAX && ///确保两点之间有弧
matrix[min_cost_index][j] + min_cost < dist[j])
{
dist[j] = matrix[min_cost_index][j] + min_cost;
path[j] = min_cost_index;
}
}
}
}
int main()
{
cout << "请输入图的顶点数(<100):";
cin >> vertex_num;
cout << "请输入图的弧数:";
cin >> arc_num;
for (int i = 0; i < vertex_num; i++)
for (int j = 0; j < vertex_num; j++)
matrix[i][j] = INT_MAX; ///初始化matrix数组
cout << "请输入弧的信息:n";
int u, v, w;
for (int i = 0; i < arc_num; i++)
{
cin >> u >> v >> w;
matrix[u][v] = matrix[v][u] = w;
}
cout << "请输入源点(<" << vertex_num << "):";
cin >> source;
Dijkstra(source);
for (int i = 0; i < vertex_num; i++)
{
if (i != source)
{
cout << source << "到" << i << "最短距离是:" << dist[i] << ",路径是:" << i;
int t = path[i];
while (t != source)
{
cout << "--" << t;
t = path[t];
}
cout << "--" << source << endl;
}
}
return 0;
}