代码中所对应的图:
最小生成树:
涉及到的知识:
1. Dijkstra算法。2. Floyd算法。3. 无向有权图的建立。4. Prim算法。
//use邻接矩阵存储的图的最短路径问题 #include <iostream> #include <malloc.h> using namespace std; const int ERROR = -100; //错误标记 const int MaxVertexNum = 100; //最大顶点数 const int MAXNUM = 65535; //∞ typedef int Vertex; //用顶点下标表示顶点,为整型 typedef int WeightType; //边的权值设为整型 typedef char DataType; //顶点存储的数据类型设为字符型 int Visited[MaxVertexNum]; //Visited[]为全局变量,用来标记节点是否被访问 int dist[MaxVertexNum]; //图中各个顶点到源点的最短路径 int p[MaxVertexNum][MaxVertexNum]; //记录Floyd问题中的路径 //MGraph类的定义 - 邻接矩阵表示的图 struct { int num; int pnode[MaxVertexNum]; }path[MaxVertexNum]; //path为从V0到各顶点的最短路径 //边的定义 typedef struct ENode *PtrToENode; struct ENode { Vertex V1, V2; //有向边<v1,v2> WeightType Weight; //权重 }; typedef PtrToENode Edge; //MGraph类的定义 template <class T> class MGraph { private: int Nv; //顶点数 int Ne; //边数 T G[MaxVertexNum][MaxVertexNum]; //邻接矩阵 public: MGraph() { Nv = 0; Ne = 0; } //构造函数 // ~MGraph(); //析构函数 bool BuildGraph(); //根据用户输入建立一个图 bool Dijkstra(Vertex s); //Dijkstra算法求最短路径 void DisDijPath(); //输出单源最短路径的result Vertex FindMinDist(int collected[]); //返回未被收录顶点中dist最小值 bool Floyd(); //Floyd算法求解多源最短路径 void PrintFloyd(); //output多源最短路径的result void Prim(MGraph& PrimTree); //最小生成树算法 void DispPrim(); //输出最小生成树 }; //MGraph类的实现 //BuildGraph() - 根据用户输入建立一个图 template <class T> bool MGraph<T>::BuildGraph() { cout << "顶点数:"; cin >> Nv; //初始化有Nv个顶点但是没有边的图 //初始化邻接矩阵 //注意:这里默认顶点编号从0开始,到(Graph->Nv-1) Vertex V, W; for (V = 0; V < Nv; V++) for (W = 0; W < Nv; W++) G[V][W] = MAXNUM; cout << "边数:"; cin >> Ne; Edge E; int i; if (Ne) //如果有边 { E = (Edge)malloc(sizeof(struct ENode)); //建立边节点 //读入边,格式为"起点、终点、权重",并插入邻接矩阵 cout << "以起点、终点、权重的格式读入边" << endl; for (i = 0; i < Ne; i++) { cin >> E->V1 >> E->V2 >> E->Weight; //插入边<v1,v2> G[E->V1][E->V2] = E->Weight; //若是无向图,还要插入边<v2,v1> G[E->V2][E->V1] = E->Weight; } } } //FindMinDist()返回未被收录顶点中的dist最小值 template <class T> Vertex MGraph<T>::FindMinDist(int collected[]) { Vertex MinV, V; int MinDist = MAXNUM; for (V = 0; V < Nv; V++) //若V未被收录,且dist[V]更小 if (collected[V] == false && dist[V] < MinDist) { MinDist = dist[V]; //更新最小距离 MinV = V; //更新对应顶点 } if (MinDist < MAXNUM) //若找到最小dist return MinV; //返回对应的顶点下标 else return ERROR; //若这样的顶点不存在,则返回错误标记 } //Dijkstra算法 - 单源最短路径 template <class T> bool MGraph<T>::Dijkstra(Vertex S) { int collected[MaxVertexNum]; Vertex V, W; //初始化:此处默认邻接矩阵中不存在边用MAXNUM表示 for (V = 0; V < Nv; V++) { dist[V] = G[S][V]; path[V].pnode[0] = S; path[V].num = 0; collected[V] = false; } //先将起点收入集合 dist[S] = 0; collected[S] = true; while (1) { //V = 未被收录的顶点中dist最小者 V = FindMinDist(collected); if (V == ERROR) //若这样的V不存在 break; //算法结束 collected[V] = true; //收录V for (W = 1; W < Nv; W++) //对于图中的每个顶点W //若W是V的邻接点并且未被收录 if (collected[W] == false && G[V][W] < MAXNUM) { if (G[V][W] < 0) //若有负边 return false; //不能正确解决,返回错误标记 //若收录V使得dist[W]变小 if (dist[V] + G[V][W] < dist[W]) { dist[W] = dist[V] + G[V][W]; //更新dist[W] path[W].num++; //更新S到W的路径 path[W].pnode[path[W].num] = V; } } path[V].num++; //将终点V加到路径中 path[V].pnode[path[V].num] = V; } return true; //算法执行完毕,返回正确标记 } //DisDijPath() - display单源最短路径result template <class T> void MGraph<T>::DisDijPath() { int i, j; cout << endl; cout << "\t从V0到各个顶点的最短路径长度如下" << endl; cout << "\t(起点->终点) 最短长度 最短路径" << endl; cout << "\t------------ ------- --------" << endl; for (i = 1; i < Nv; i++) { cout << "\t (V0->V" << i << "): "; if (dist[i] < MAXNUM) cout << " " << dist[i] << " ("; else cout << "∞ ("; // cout << endl; for (j = 0; j < path[i].num; j++) cout << "V" << path[i].pnode[j] << ", "; cout << "V" << path[i].pnode[path[i].num] << ")"; cout << endl; } } //Floyd() - 多源最短路问题 template <class T> bool MGraph<T>::Floyd() { Vertex i, j, k; int D[MaxVertexNum][MaxVertexNum]; //初始化 for (i = 0; i < Nv; i++) for (j = 0; j < Nv; j++) { D[i][j] = G[i][j]; p[i][j] = j; } //Floyd核心算法 for (k = 0; k < Nv; k++) for (i = 0; i < Nv; i++) for (j = 0; j < Nv; j++) if (D[i][k] + D[k][j] < D[i][j]) { D[i][j] = D[i][k] + D[k][j]; if (i == j && D[i][j] < 0) //若发现负值圈 return false; //不能正确解决,返回错误标记 p[i][j] = k; } return true; } //PrintFloyd() - output多源最短路径问题的result template <class T> void MGraph<T>::PrintFloyd() { cout << "各个顶点对的最短路径:" << endl; int row = 0; int col = 0; int temp = 0; for (row = 0; row < Nv; row++) { for (col = row + 1; col < Nv; col++) { cout << "v" << row << "---" << "v" << col << " p: " << " v" << row; temp = p[row][col]; //循环输出途径的每条路径。 while (temp != col) { cout << "-->" << "v" << temp; temp = p[temp][col]; } cout << "-->" << "v" << col << endl; } cout << endl; } } //Prim() - 最小生成树算法 template <class T> void MGraph<T>::Prim(MGraph& PrimTree) { bool visited[MaxVertexNum]; int i, j, k, h; int power, power_j, power_k; for (i = 0; i < Nv; i++) visited[i] = false; PrimTree.Nv = Nv; for (i = 0; i < Nv; i++)//初始化矩阵 { for (j = 0; j < Nv; j++) { PrimTree.G[i][j] = MAXNUM; } } visited[0] = true; for (i = 0; i < Nv; i++) { power = MAXNUM; for (j = 0; j < Nv; j++) { if (visited[j]) { for (k = 0; k < Nv; k++) { if (power > G[j][k] && !visited[k]) { power = G[j][k]; power_j = j; power_k = k; } } } } //min power if (!visited[power_k]) { visited[power_k] = true; PrimTree.G[power_j][power_k] = power; } } } //DispPrim() - 输出最小生成树 template <class T> void MGraph<T>::DispPrim() { int i, j; for (i = 0; i < Nv; i++) { for (j = 0; j < Nv; j++) { cout << "\t" << G[i][j]; } cout << endl; } } int main() { MGraph<int> mGraph; MGraph<int> PrimTree; //建立图 mGraph.BuildGraph(); //求解单源最短路径 mGraph.Dijkstra(0); mGraph.DisDijPath(); //求解多源最短路径 mGraph.Floyd(); mGraph.PrintFloyd(); //最小生成树 mGraph.Prim(PrimTree); PrimTree.DispPrim(); return 0; }
运行结果:
顶点数:5
边数:6
以起点、终点、权重的格式读入边
0 1 7
0 2 2
2 3 3
1 3 9
3 4 4
2 4 15
边数:6
以起点、终点、权重的格式读入边
0 1 7
0 2 2
2 3 3
1 3 9
3 4 4
2 4 15
从V0到各个顶点的最短路径长度如下
(起点->终点) 最短长度 最短路径
------------ ------- --------
(V0->V1): 7 (V0, V1)
(V0->V2): 2 (V0, V2)
(V0->V3): 5 (V0, V2, V3)
(V0->V4): 9 (V0, V2, V3, V4)
各个顶点对的最短路径:
v0---v1 p: v0-->v1
v0---v2 p: v0-->v2
v0---v3 p: v0-->v2-->v3
v0---v4 p: v0-->v3-->v4
(起点->终点) 最短长度 最短路径
------------ ------- --------
(V0->V1): 7 (V0, V1)
(V0->V2): 2 (V0, V2)
(V0->V3): 5 (V0, V2, V3)
(V0->V4): 9 (V0, V2, V3, V4)
各个顶点对的最短路径:
v0---v1 p: v0-->v1
v0---v2 p: v0-->v2
v0---v3 p: v0-->v2-->v3
v0---v4 p: v0-->v3-->v4
v1---v2 p: v1-->v0-->v2
v1---v3 p: v1-->v3
v1---v4 p: v1-->v3-->v4
v1---v3 p: v1-->v3
v1---v4 p: v1-->v3-->v4
v2---v3 p: v2-->v3
v2---v4 p: v2-->v3-->v4
v2---v4 p: v2-->v3-->v4
v3---v4 p: v3-->v4
65535 7 2 65535 65535
65535 65535 65535 65535 65535
65535 65535 65535 3 65535
65535 65535 65535 65535 4
65535 65535 65535 65535 65535
--------------------------------
Process exited after 56.5 seconds with return value 0
请按任意键继续. . .
Process exited after 56.5 seconds with return value 0
请按任意键继续. . .