五、图的应用
1.实验目的
(1)掌握图的相关概念,包括图、有向图、无向图、子图、连通图、度、入度、出度、简单回路、环等;
(2)掌握图的各种存储结构,包括邻接矩阵和邻接表等;
(3)掌握图的基本运算,包括创建图、输出图、深度优先遍历、广度优先遍历等;
(4)掌握图的其他运算,包括最小生成树、最短路径、拓扑排序和关键路径等算法。
2.实验内容
利用Prim算法求网的最小生成树。
要求和提示:设图的顶点数为10个。为简单起见,网中边的权值设成小于100的整数,可利用C语言的rand()函数产生。
3.源程序和实验结果
#include <iostream> #include <string> #include <iomanip> #include <cstdlib> #define INT_max 100000 //借此表示无穷大 #define Num 10 //表示顶点个数 10个顶点 using namespace std; struct Graph { int vexnum; //顶点个数 int arcnum; //边的条数 int **arcs; //邻接矩阵 string *vexs; //顶点向量 }; typedef struct { string adjvex; //该边依附在U中的顶点 int lowcost; //存储该边上的权 } closedge; void createGraph(Graph &g); // 创建图 void print(Graph g); // 打印图 void miniSpanTree_PRIM(Graph g, string u); //普利姆算法求最小生成树 int locateVex(Graph g, string u); //确定顶点u在图g中位置 int minimum(closedge *closedge); //求T的下一个结点 int main() { Graph g; createGraph(g); cout << "构造好后图的邻接矩阵为:" << endl; print(g); int start = 0; //从编号为start的顶点开始 miniSpanTree_PRIM(g, g.vexs[start]); return 0; } void createGraph(Graph &g) { g.vexnum = Num; //顶点数目为10 cout << "输入边的条数" << endl; cin >> g.arcnum; g.vexs = new string[g.vexnum]; g.arcs = new int *[g.vexnum]; // 初始化 for (int i = 0; i < g.vexnum; i++) { g.vexs[i] = "v" + std::to_string(i); //对每个顶点进行命名 g.arcs[i] = new int[g.vexnum]; for (int j = 0; j < g.vexnum; j++) g.arcs[i][j] = INT_max; } cout << "请输入每条边的顶点编号(0-9),权值由随机函数生成(1-100)" << endl; srand(1); //随机种子,保证每次随机数相同 for (int i = 0; i < g.arcnum; i++) { int start, end, weight; cin >> start >> end; weight = rand() % 99 + 1; g.arcs[start][end] = weight; g.arcs[end][start] = weight; } } void print(Graph g) { for (int i = 0; i < g.vexnum; i++) { for (int j = 0; j < g.vexnum; j++) { if (g.arcs[i][j] == INT_max) cout << left << setw(6) << "∞"; else cout << left << setw(6) << g.arcs[i][j]; } cout << endl; } } void miniSpanTree_PRIM(Graph g, string u) { //用普利姆算法从第u个顶点出发构造网g的最小生成树T,输出T的各条边。 //记录从顶点集U到V-U的代价最小的边的辅助数组定义: closedge closedge[g.vexnum]; int k = locateVex(g, u); //辅助数组初始化 for (int j = 0; j < g.vexnum; j++) if (j != k) closedge[j] = {u, g.arcs[k][j]}; closedge[k].lowcost = 0; for (int i = 1; i < g.vexnum; i++) //选择其余g.vexnum-1个顶点 { k = minimum(closedge); //求出T的下一个结点:第k结点 cout << closedge[k].adjvex << "------->" << g.vexs[k] << " 权值为:" << closedge[k].lowcost << endl; closedge[k].lowcost = 0; //第k顶点并入U集 for (int j = 0; j < g.vexnum; j++) //新顶点并入U后重新选择最小边 if (g.arcs[k][j] < closedge[j].lowcost) closedge[j] = {g.vexs[k], g.arcs[k][j]}; } } int locateVex(Graph g, string u) { int i; for (i = 0; i < g.vexnum; i++) { if (g.vexs[i] == u) return i; } if (i == g.vexnum) { cout << "该顶点不在图中..." << endl; } return -1; } int minimum(closedge *closedge) { int i, min, k; for (i = 0, min = INT_max; i < Num; i++) { if (closedge[i].lowcost > 0 && closedge[i].lowcost < min) { min = closedge[i].lowcost; k = i; } } return k; }
测试数据:
16
0 1
0 4
0 5
0 9
1 2
1 6
1 9
2 4
2 8
3 6
3 7
3 9
4 7
5 8
6 9
7 8
构造出来的无向网:
输出结果截图:
4.分析与讨论
如何使用邻接矩阵构造无向网
如何使用prim算法构造最小生成树