一、基本概念
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;
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行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100
Sample Output
3 ?
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 }