程序小白,希望和大家多交流,共同学习
//迪杰斯特拉(dijkstra)算法,计算最短路径
#include<iostream>
#include<string>
#include<cstdio>
#include<stack>
#define MAX_VN 50
#define INF 23767
using namespace std;
//顶点信息
typedef string VertexData;
//临接矩阵
struct AdjMatrix{
VertexData vertex[MAX_VN];
int arcs[MAX_VN][MAX_VN];
int verNum, arcNum;
};
void createAdjMatrix(AdjMatrix &G);
int locateVertex(AdjMatrix &G, VertexData data);
void outputAdjMatrix(AdjMatrix &G);
//Dijkstra
void dijkstra(AdjMatrix &G);
void dijkstra(const AdjMatrix &G, int v, int *dist, int *pre);
int chooseMin(const AdjMatrix &G, int *dist, bool *mark);
void printDijkstra(const AdjMatrix &G, int v, int *dist, int *pre);
int main(){
/*
6 10
v1 v2 v3 v4 v5 v6
v1 v2 5
v1 v4 7
v2 v3 4
v3 v1 8
v3 v6 9
v4 v3 5
v4 v6 6
v5 v4 5
v6 v1 2
v6 v5 1
*/
AdjMatrix G;
createAdjMatrix(G);
outputAdjMatrix(G);
dijkstra(G);
return 0;
}
void createAdjMatrix(AdjMatrix &G){
cout << "输入顶点个数和弧的条数:";
cin >> G.verNum >> G.arcNum;
cout << "输入各个顶点信息:";
for (int i = 0; i < G.verNum; i++){
cin >> G.vertex[i];
}
cout << "输入各条弧的信息:";
//初始化各个顶点之间的距离为INF
for (int i = 0; i < G.verNum; i++){
for (int j = 0; j < G.verNum; j++){
G.arcs[i][j] = INF;
}
}
//输入各条弧信息
VertexData u, v;
int j, k, w;
for (int i = 0; i < G.arcNum; i++){
cin >> u >> v >> w;
j = locateVertex(G, u);
k = locateVertex(G, v);
G.arcs[j][k] = w;
}
}
int locateVertex(AdjMatrix &G, VertexData data){
for (int i = 0; i < G.verNum; i++){
if (G.vertex[i] == data){
return i;
}
}
return -1;
}
void outputAdjMatrix(AdjMatrix &G){
for (int i = 0; i < G.verNum; i++){
for (int j = 0; j < G.verNum; j++){
if (G.arcs[i][j] == INF){
cout << "∞ ";
}
else
printf("%-3d", G.arcs[i][j]);
}
cout << endl;
}
}
//Dijkstra
void dijkstra(AdjMatrix &G){
int n = G.verNum;//顶点个数
int *dist = new int[n];//用来计算到每个顶点的最短路径
int *pre = new int[n];//用来标记每个顶点的前驱是谁,也就是到这个点的前一个点(最短路径)
VertexData data;
cout << "选择起始点:";
cin >> data;
int v = locateVertex(G, data);
dijkstra(G, v, dist, pre);//找打到各个顶点的最短路径,长度保存在dist中,每个顶点前驱保存在pre中
printDijkstra(G, v, dist, pre);//根据长度和pre打印到各个顶点的路径状况
delete []dist;
delete []pre;
}
void dijkstra(const AdjMatrix &G, int v, int *dist, int *pre){
cout << "dijkstra\n";
int n = G.verNum;
//mark用来记录每个顶点书否已经在最短路径中
bool *mark = new bool[n];
//初始化各个信息,dist为了 保存最短路径,所以设置为最大值
//前驱未定,设置为-1,所有顶点未标记
for (int i = 0; i < n; i++){
dist[i] = INF;
pre[i] = -1;
mark[i] = false;
}
//根据已有的起始点标记一些值
dist[v] = 0;
mark[v] = true;
for (int i = 0; i < n; i++){
if (G.arcs[v][i] != INF){
dist[i] = G.arcs[v][i];//目前,是第一个点,所有可以到达v的顶点的最短路径值,就是已有的权值
pre[i] = v;//当然可以到这些点的前驱就是顶点v
}
}
//接下来要把其他的顶点的信息,在dist和pre中进行标记
for (int i = 1; i < n; i++){
int m = chooseMin(G, dist, mark);//找出dist中的最小值,实际上是找到邻接点的最小值
//cout << m << endl;
if(m != -1){
mark[m] = true;
for (int j = 0; j < n; j++){//最小值加上最小值顶点的邻接点的权值小于dist中的记录
//就需要更新dist此时的状况是走多的结点,但是权值总和最少
//当然此时结点的前驱结点就改变了
if (!mark[j] && dist[m] + G.arcs[m][j] < dist[j]){
dist[j] = dist[m] + G.arcs[m][j];
pre[j] = m;
}
}
}
}
delete []mark;
}
int chooseMin(const AdjMatrix &G, int *dist, bool *mark){
int n = G.verNum, k, min = INF;
for (int i = 0; i < n; i++){
if (!mark[i] && dist[i] < min){//在未标记的顶点中找到最小值对应的顶点
k = i;
min = dist[i];
}
}
if (min < INF){
return k;
}
return -1;//没有最小值返回-1
}
//打印Dijkstra
//此时已知没有被更新的顶点是起始点和终止点,pre都为-1
//因为pre中存的都是前驱,所以将它的前驱顺次保存在栈中,在从栈顶顺次输出,就是最短路径了
void printDijkstra(const AdjMatrix &G, int v, int *dist, int *pre){
cout << "print\n";
stack<int> s;
int n = G.verNum;
for (int i = 0; i < n; i++){
if (i != v){
//将顶点i的前驱顺次入栈
s.push(i);
int t = pre[i];
while (t != -1){
s.push(t);
t = pre[t];
}
//现在出栈
int h = s.top();
s.pop();
cout << G.vertex[h];
while (!s.empty()){
h = s.top();
s.pop();
cout << " --> " << G.vertex[h];
}
if (dist[i] != INF){
cout << " : " << dist[i] << endl;
}
else
cout << " can't reached" << endl;
}
}
}