前面的一篇文章最短路没有带回溯,这里补充一个带回溯版本的,算法还是 Dijkstra 算法,前面的文章:最短路 Dijkstra 和 Floyd 算法,例子还是那个那篇笔记的例子,图存储结构还是邻接矩阵,算法封装到了一个类中,图和代码如下:
#include <vector>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
class Graph {
private:
int *graph; // 邻接矩阵
int vertexNum; // 顶点个数
int unreachDis; // 不可达
public:
Graph(int *graph, int vertexNum, int unreachDis) {
this->graph = new int[vertexNum * vertexNum];
std::memcpy(this->graph, graph, sizeof(int) * vertexNum * vertexNum);
this->vertexNum = vertexNum;
this->unreachDis = unreachDis;
}
struct node {
int vertex;
int distance; //距离start的距离
struct node *previous;
bool isVisited;
bool operator< (const node& a) const{
return distance > a.distance;
} // 为了实现最小堆
};
void getShortPath(int start, int end, int &distance, std::vector<int> &path) {
if (start < 0 || start >= vertexNum) {
printf("start invalid\n");
return;
}
if (end < 0 || end >= vertexNum) {
printf("end invalid\n");
return;
}
node *nodes = new node[vertexNum];
for (int i = 0; i < vertexNum; i++) {
nodes[i].vertex = i;
nodes[i].distance = unreachDis;
nodes[i].previous = NULL;
nodes[i].isVisited = false;
}
nodes[start].distance = 0;
std::priority_queue<node> que;
que.push(nodes[start]);
while (!que.empty() && !nodes[end].isVisited) {
// 找出未访问过的离 start 的最近的点
int minDistance = que.top().distance;
int minVertex = que.top().vertex;
que.pop();
// 下面比较关键,因为一个点可能压进去多次
if (nodes[minVertex].isVisited == true )
continue;
// 对所有从 minVertex 出发的边进行松弛
nodes[minVertex].isVisited = true;
for (int i = 0; i < vertexNum; i++) {
if (!nodes[i].isVisited && graph[minVertex * vertexNum + i] != unreachDis) {
if (nodes[i].distance > minDistance + graph[minVertex * vertexNum + i]) {
nodes[i].distance = minDistance + graph[minVertex * vertexNum + i];
nodes[i].previous = &nodes[minVertex];
que.push(nodes[i]);
}
}
}
}
if (!nodes[end].isVisited)
printf("no path\n");
distance = nodes[end].distance;
node *pnode = &nodes[end];
while (pnode != NULL) {
path.push_back(pnode->vertex);
pnode = pnode->previous;
}
std::reverse(path.begin(), path.end());
delete [] nodes;
}
virtual ~Graph() {
delete[] graph;
}
};
void printPath(int start, int end, int distance, std::vector<int> &path) {
printf("distance from %d to %d is %2d, ", start, end , distance);
printf("path: ");
for (unsigned int i = 0; i < path.size(); i++) {
printf("%d ", path[i]);
}
printf("\n");
}
int main() {
int N = 65536, num = 9;
int graph[9][9] = {
{0, 1, 5, N, N, N, N, N, N},
{1, 0, 3, 7, 5, N, N, N, N},
{5, 3, 0, N, 1, 7, N, N, N},
{N, 7, N, 0, 2, N, 3, N, N},
{N, 5, 1, 2, 0, 3, 6, 9, N},
{N, N, 7, N, 3, 0, N, 5, N},
{N, N, N, 3, 6, N, 0, 2, 7},
{N, N, N, N, 9, 5, 2, 0, 4},
{N, N, N, N, N, N, 7, 4, 0}
};
Graph graphTest((int *)graph, num, N);
int start = 0, end = 2;
int distance = 0;
std::vector<int> path;
for (end = 0; end < num; end++) {
path.clear();
graphTest.getShortPath(start, end, distance, path);
printPath(start, end, distance, path);
}
return 0;
}
运行结果如下:
distance from 0 to 0 is 0, path: 0
distance from 0 to 1 is 1, path: 0 1
distance from 0 to 2 is 4, path: 0 1 2
distance from 0 to 3 is 7, path: 0 1 2 4 3
distance from 0 to 4 is 5, path: 0 1 2 4
distance from 0 to 5 is 8, path: 0 1 2 4 5
distance from 0 to 6 is 10, path: 0 1 2 4 3 6
distance from 0 to 7 is 12, path: 0 1 2 4 3 6 7
distance from 0 to 8 is 16, path: 0 1 2 4 3 6 7 8
Program ended with exit code: 0