最小生成树-Prim算法
一、基本概念
1.连通图:在无向图中,若任意两个顶点都有路径相通,则称该无向图为连通图。
2.连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。
3.生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。
4.最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
二、prim算法
- 基本思想:
取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w。在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。之后继续往生成树上添加顶点,直至生成树上含有 n 个顶点为止。
一般情况下所添加的顶点应满足下列条件:
在生成树的构造过程中,图中 n 个顶点分属两个集合:已落在生成树上的顶点集 U 和尚未落在生成树上的顶点集V-U ,则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边。
需要设一个辅助数组:
struct node{
VertexData AdjVertex;
int lowestcost;
}closedge[105];
用下标表示未在生成树上的点,AdjVertex存储在生成树上的点,两点连成一个边,lowestcost表示权值,。最后得到的数组中存储的就是最小生成树的边。
- 过程图示:
- 代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define VertexData int 6 #define INFINITE 1000000007 7 8 typedef struct{ 9 int AdjMatrix[105][105]; // 邻接矩阵 10 int vertex_num; // 点的个数 11 //int arc_num; 12 //VertexData vertex[105]; 13 }Graph; 14 15 struct node{ 16 VertexData AdjVertex; // 生成树中的点 17 int lowestcost; // 权值 18 }closedge[105]; 19 char vextex[] = { 'A', 'B', 'C', 'D', 'E', 'F' }; 20 21 // 初始化邻接矩阵 22 void Build_Matrix(Graph *G) { 23 for (int i = 0; i < G->vertex_num; i++) 24 for (int j = 0; j < G->vertex_num; j++) { 25 G->AdjMatrix[i][j] = INFINITE; 26 G->AdjMatrix[j][i] = INFINITE; 27 } 28 } 29 30 // 返回最小权值的边 31 int getmin(int n) { 32 int Min = INFINITE; 33 int index = -1; 34 for(int i = 0; i < n; i++) { 35 if(closedge[i].lowestcost && closedge[i].lowestcost < Min) { 36 Min = closedge[i].lowestcost; 37 index = i; 38 } 39 } 40 return index; 41 } 42 43 // prim算法 44 void prim(Graph G, VertexData s) { 45 // 初始化辅助数组 46 for (int i = 0; i < G.vertex_num; i++) { 47 closedge[i].lowestcost = INFINITE; 48 } 49 // 先存入起始点 50 closedge[s].AdjVertex = s; 51 closedge[s].lowestcost = 0; 52 for(int i = 0; i < G.vertex_num; i++) { 53 if(i != s) { 54 closedge[i].AdjVertex = s; 55 closedge[i].lowestcost = G.AdjMatrix[s][i]; 56 } 57 } 58 // 最多循环顶点个数n-1次 59 for(int i = 0; i < G.vertex_num-1; i++) { 60 int k = getmin(G.vertex_num); 61 if(k == -1) break; 62 cout << vextex[closedge[k].AdjVertex] << "--" << vextex[k] << endl; 63 closedge[k].lowestcost = 0; // 权值赋0表示将该点并入最小生成树的集合 64 // 更新树外最小代价边的信息 65 for(int j = 0; j < G.vertex_num; j++) { 66 if(G.AdjMatrix[k][j] < closedge[j].lowestcost) { 67 closedge[j].lowestcost = G.AdjMatrix[k][j]; 68 closedge[j].AdjVertex = k; 69 } 70 } 71 } 72 } 73 74 int main() { 75 int m, n, a, b; 76 Graph G; 77 78 int ans = 0, cost, counter = 0; 79 cout << "输入点个数" << endl; 80 cin >> m; 81 G.vertex_num = m; 82 Build_Matrix(&G); 83 cout << "输入边个数" << endl; 84 cin >> n; 85 cout << "输入边信息" << endl; 86 for (int i = 0; i < n; i++) { 87 cin >> a >> b >> cost; 88 G.AdjMatrix[a][b] = cost; 89 G.AdjMatrix[b][a] = cost; 90 } 91 prim(G, 0); 92 return 0; 93 } 94 95 96 /* 97 * 98 99 6 100 10 101 0 1 6 102 0 2 1 103 0 3 5 104 1 2 5 105 1 4 3 106 2 3 5 107 2 4 6 108 2 5 4 109 3 5 2 110 4 5 6 111 * */ 112 /* 113 int locate(Graph G, char c) { 114 for(int i = 0; i < G.vertex_num; i++) { 115 if(G.vertex[i] == c) 116 return i; 117 } 118 return -1; 119 } 120 */
三、例题
通畅工程:
Description
Input
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
Sample Input
Sample Output
ac代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define VertexData int 6 #define INFINITE 10000000007 7 8 typedef struct{ 9 //VertexData vertex[1005]; 10 int AdjMatrix[105][105]; 11 //int arc_num; 12 int vertex_num; 13 }Graph; 14 15 struct node{ 16 VertexData AdjVertex; 17 int lowestcost; 18 }closedge[105]; 19 20 21 void Build_Matrix(Graph *G) { 22 for (int i = 0; i < G->vertex_num; i++) 23 for (int j = 0; j < G->vertex_num; j++) { 24 G->AdjMatrix[i][j] = INFINITE; 25 G->AdjMatrix[j][i] = INFINITE; 26 } 27 } 28 29 int getmin(struct node *closedge, int n) { 30 int Min = INFINITE; 31 int index = -1; 32 for(int i = 0; i < n; i++) { 33 if(closedge[i].lowestcost && closedge[i].lowestcost < Min) { 34 Min = closedge[i].lowestcost; 35 index = i; 36 } 37 } 38 return index; 39 } 40 41 void prim(Graph G, VertexData s) { 42 for (int i = 0; i < G.vertex_num; i++) { 43 closedge[i].lowestcost = INFINITE; 44 } 45 closedge[s].AdjVertex = s; 46 closedge[s].lowestcost = 0; 47 for(int i = 0; i < G.vertex_num; i++) { 48 if(i != s) { 49 closedge[i].AdjVertex = s; 50 closedge[i].lowestcost = G.AdjMatrix[s][i]; 51 } 52 } 53 for(int i = 0; i < G.vertex_num-1; i++) { 54 int k = getmin(closedge, G.vertex_num); 55 if(k == -1) break; 56 closedge[k].lowestcost = 0; 57 for(int j = 0; j < G.vertex_num; j++) { 58 if(G.AdjMatrix[k][j] < closedge[j].lowestcost) { 59 closedge[j].lowestcost = G.AdjMatrix[k][j]; 60 closedge[j].AdjVertex = k; 61 } 62 } 63 } 64 } 65 66 int main() { 67 int m, n, a, b; 68 Graph G; 69 while(~scanf("%d%d", &n, &m)) { 70 if(!n) break; 71 int ans = 0, cost, counter = 0; 72 G.vertex_num = m; 73 Build_Matrix(&G); 74 for (int i = 0; i < n; i++) { 75 cin >> a >> b >> cost; 76 G.AdjMatrix[a-1][b-1] = cost; 77 G.AdjMatrix[b-1][a-1] = cost; 78 } 79 80 prim(G, 0); 81 for(int i = 1; i < m; i++) { 82 if(closedge[i].lowestcost == 0) { 83 ans += G.AdjMatrix[i][closedge[i].AdjVertex]; 84 counter++; 85 } 86 } 87 if(counter != m-1) 88 cout << "?" << endl; 89 else 90 cout << ans << endl; 91 } 92 return 0; 93 }
参考博客:https://blog.csdn.net/a2392008643/article/details/81781766