问题引入:在有权值的图结构中(网)的各个顶点中,顶点之间的最短距离是多大?
应用:计算机的网络路由,机器人探路问题,游戏指引系统等等。
关于图的最短路径问题的一般可以分成以下两种:
其实对图中的顶点使用迪杰斯特拉算法即可求得图中每两个顶点之间的最短距离。
这是一个非常易于理解的算法(嗯…数学解释好像还是有点复杂),简单来看就是使用暴力搜索的方式。怎么样计算两个顶点之间的最短距离呢?先获得这两个顶点的距离,看有没有其他路径比之更短就是了,简单粗暴的方法就是使用循环进行遍历啦。
算法过程如下:
代码实现:
#include
#include
#include
using namespace std;
/**
* - g 表示由邻接矩阵结构表示的图 - 0坐标不使用, 最大值设置为1e18
* - n 表示顶点的数量
*/
void flody(int **g, int n) {
int D[n + 1][n + 1]; //0索引不使用
memset(D, 127 / 3, sizeof(D)); //设置为一个极大值
for (int i = 1; i <= n; i++) { //初始化D数组,将其值初始化为图中边的权重
for (int j = 1; j <= n; j++) {
if (g[i][j] != 1e18) {
D[i][j] = g[i][j];
}
}
D[i][i] = 0; //顶点自身的权重为0
}
//三重循环遍历,下面的变量可以看成是顶点的位置
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
if (D[i][j] < D[i][k] + D[k][j]) { //存在一个中间顶点k是的i,j之间的距离更小, 则替换该值
D[i][j] = D[i][k] + D[k][j];
}
}
}
}
//最后的D数组可以根据需要返回或者打印出来看一下效果
}
备注:上面其实可以不用另外创建一个D数组初始化操作的,可以发现D数组初始化完成后基本和图的邻接矩阵是一样的,因此可以直接对图进行操作,但是这样会改变邻接举证原本的结构,即图原本的信息如果没有再保存起来可能会丢失,可以根据实际情况来~
时间复杂度:除去一些初始化的操作,程序的主体很明显是那三重循环,所以其时间复杂度为O(n^3)的。
与Flody算法是计算每两个顶点之间的最短距离不同的是,迪杰斯特拉算法计算的是从一个源点出发,计算其到图中其他指定顶点的最短距离。
算法过程如下:
注:上面的vi均用下标值表示顶点
代码实现:
#include
#include
#include
using namespace std;
int getMinEdge(int *D, int n, int *U) {
int min = 1 << 30, index = 0;
for (int i = 1; i <= n; i++) {
if (U[i] == 0 && D[i] < min) {
min = D[i];
index = i;
}
}
return index;
}
int main() {
cin >> n >> m;
int a[n + 1][n + 1], D[n + 1];
memset(a, 127/3, sizeof(a));
int x, y, z;
for (int i = 1; i <= m; i++) {
cin >> x >> y >> z;
a[x][y] = z;
if (x == 1) { //假设顶点v1为源点, 初始化D数组
D[y] = z;
} else {
D[y] = 1 << 30; //其他和v1无直接关联的边的设置为一个极大值
}
}
int U[n + 1] = {0}; //用0来表示该顶点还没有被确定最短距离
U[1] = 1; //1 表示该顶点已经被确定最短距离了v1是源点的最短距离一开始就能确定下来
for (int i = 1; i <= n; i++) {
int k = getMin(D, n, U);
U[k] = 1;
for (int j = 1; j <= n; j++) {
if (U[j] == 0 && a[k][j] + D[k] < D[j]) { //更新源点到其他顶点的最短距离
D[j] = a[k][j] + D[k];
}
}
}
for (int i = 1; i <= n; i++) {
printf("%d\t", D[i]);
}
}
时间复杂度:程序中除去那些初始化的操作,主体就是两个for循环了,因此其时间复杂度为O(n^2),如果对每一个顶点使用迪杰斯特拉算法,则其时间复杂度为O(n**3),和Flody算法一样。
测试用例
输入:
4 4
1 2 4
2 3 7
2 4 1
3 4 6
输出:0 4 11 5