1 /* 图的邻接矩阵表示法 */
2 #include <cstdio>
3 #include <stdlib.h>
4
5 #define MaxVertexNum 1001 /* 最大顶点数设为100 */
6 #define INFINITY 65535 /* ∞设为双字节无符号整数的最大值65535*/
7 #define ERROR -1
8 typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
9 typedef int WeightType; /* 边的权值设为整型 */
10
11
12 /* 边的定义 */
13 typedef struct ENode *PtrToENode;
14 struct ENode{
15 Vertex V1, V2; /* 有向边<V1, V2> */
16 WeightType Weight; /* 权重 */
17 };
18 typedef PtrToENode Edge;
19
20 /* 图结点的定义 */
21 typedef struct GNode *PtrToGNode;
22 struct GNode{
23 int Nv; /* 顶点数 */
24 int Ne; /* 边数 */
25 WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
26 };
27 typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
28
29
30
31
32
33 /* 邻接点的定义 */
34 typedef struct AdjVNode *PtrToAdjVNode;
35 struct AdjVNode{
36 Vertex AdjV; /* 邻接点下标 */
37 WeightType Weight; /* 边权重 */
38 PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
39 };
40
41 /* 顶点表头结点的定义 */
42 typedef struct Vnode{
43 PtrToAdjVNode FirstEdge;/* 边表头指针 */
44 } AdjList[MaxVertexNum]; /* AdjList是邻接表类型 */
45
46 /* 图结点的定义 */
47 typedef struct GNode2 *PtrToGNode2;
48 struct GNode2{
49 int Nv; /* 顶点数 */
50 int Ne; /* 边数 */
51 AdjList G; /* 邻接表 */
52 };
53 typedef PtrToGNode2 LGraph; /* 以邻接表方式存储的图类型 */
54
55
56
57 LGraph CreateGraph2( int VertexNum )
58 { /* 初始化一个有VertexNum个顶点但没有边的图 */
59 Vertex V;
60 LGraph Graph;
61
62 Graph = (LGraph)malloc( sizeof(struct GNode) ); /* 建立图 */
63 Graph->Nv = VertexNum;
64 Graph->Ne = 0;
65 /* 初始化邻接表头指针 */
66 /* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
67 for (V=0; V<Graph->Nv; V++)
68 Graph->G[V].FirstEdge = NULL;
69
70 return Graph;
71 }
72
73 void InsertEdge2( LGraph Graph, Edge E )
74 {
75 PtrToAdjVNode NewNode;
76
77 /* 插入边 <V1, V2> */
78 /* 为V2建立新的邻接点 */
79 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
80 NewNode->AdjV = E->V2;
81 NewNode->Weight = E->Weight;
82 /* 将V2插入V1的表头 */
83 NewNode->Next = Graph->G[E->V1].FirstEdge;
84 Graph->G[E->V1].FirstEdge = NewNode;
85
86 /* 若是无向图,还要插入边 <V2, V1> */
87 /* 为V1建立新的邻接点 */
88 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
89 NewNode->AdjV = E->V1;
90 NewNode->Weight = E->Weight;
91 /* 将V1插入V2的表头 */
92 NewNode->Next = Graph->G[E->V2].FirstEdge;
93 Graph->G[E->V2].FirstEdge = NewNode;
94 }
95
96 LGraph BuildGraph2()
97 {
98 LGraph Graph;
99 Edge E;
100 int Nv, i;
101
102 scanf("%d", &Nv); /* 读入顶点个数 */
103 Graph = CreateGraph2(Nv); /* 初始化有Nv个顶点但没有边的图 */
104
105 scanf("%d", &(Graph->Ne)); /* 读入边数 */
106 if ( Graph->Ne != 0 ) { /* 如果有边 */
107 E = (Edge)malloc( sizeof(struct ENode) ); /* 建立边结点 */
108 /* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
109 for (i=0; i<Graph->Ne; i++) {
110 scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
111 /* 注意:如果权重不是整型,Weight的读入格式要改 */
112 InsertEdge2( Graph, E );
113 }
114 }
115
116
117 return Graph;
118 }
119
120
121 Vertex FindMinDist( MGraph Graph, WeightType dist[] )
122 { /* 返回未被收录顶点中dist最小者 */
123 Vertex MinV, V;
124 WeightType MinDist = INFINITY;
125
126 for (V=0; V<Graph->Nv; V++) {
127 if ( dist[V]!=0 && dist[V]<MinDist) {
128 /* 若V未被收录,且dist[V]更小 */
129 MinDist = dist[V]; /* 更新最小距离 */
130 MinV = V; /* 更新对应顶点 */
131 }
132 }
133 if (MinDist < INFINITY) /* 若找到最小dist */
134 return MinV; /* 返回对应的顶点下标 */
135 else return ERROR; /* 若这样的顶点不存在,返回-1作为标记 */
136 }
137
138 int Prim( MGraph Graph)
139 { /* 将最小生成树保存为邻接表存储的图MST,返回最小权重和 */
140 WeightType dist[MaxVertexNum], TotalWeight;
141 Vertex parent[MaxVertexNum], V, W;
142 int VCount;
143 Edge E;
144
145 /* 初始化。默认初始点下标是0 */
146 for (V=0; V<Graph->Nv; V++) {
147 /* 这里假设若V到W没有直接的边,则Graph->G[V][W]定义为INFINITY */
148 dist[V] = Graph->G[0][V];
149 parent[V] = 0; /* 暂且定义所有顶点的父结点都是初始点0 */
150 }
151 TotalWeight = 0; /* 初始化权重和 */
152 VCount = 0; /* 初始化收录的顶点数 */
153
154 /* 创建包含所有顶点但没有边的图。注意用邻接表版本 */
155 LGraph MST = CreateGraph2(Graph->Nv);
156 E = (Edge)malloc( sizeof(struct ENode) ); /* 建立空的边结点 */
157
158 /* 将初始点0收录进MST */
159 dist[0] = 0;
160 VCount ++;
161 parent[0] = -1; /* 当前树根是0 */
162
163 while (1) {
164 V = FindMinDist( Graph, dist );
165 /* V = 未被收录顶点中dist最小者 */
166 if ( V==ERROR ) /* 若这样的V不存在 */
167 break; /* 算法结束 */
168
169 /* 将V及相应的边<parent[V], V>收录进MST */
170 E->V1 = parent[V];
171 E->V2 = V;
172 E->Weight = dist[V];
173 InsertEdge2( MST, E );
174 TotalWeight += dist[V];
175 dist[V] = 0;
176 VCount++;
177
178 for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W */
179 if ( dist[W]!=0 && Graph->G[V][W]<INFINITY ) {
180 /* 若W是V的邻接点并且未被收录 */
181 if ( Graph->G[V][W] < dist[W] ) {
182 /* 若收录V使得dist[W]变小 */
183 dist[W] = Graph->G[V][W]; /* 更新dist[W] */
184 parent[W] = V; /* 更新树 */
185 }
186 }
187 } /* while结束*/
188 if ( VCount < Graph->Nv ) /* MST中收的顶点不到|V|个 */
189 TotalWeight = ERROR;
190 return TotalWeight; /* 算法执行完毕,返回最小权重和或错误标记 */
191 }
192
193
194
195 MGraph CreateGraph( int VertexNum )
196 { /* 初始化一个有VertexNum个顶点但没有边的图 */
197 Vertex V, W;
198 MGraph Graph;
199
200 Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立图 */
201 Graph->Nv = VertexNum;
202 Graph->Ne = 0;
203 /* 初始化邻接矩阵 */
204 /* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
205 for (V=0; V<Graph->Nv; V++)
206 for (W=0; W<Graph->Nv; W++)
207 Graph->G[V][W] = INFINITY;
208
209 return Graph;
210 }
211
212 void InsertEdge( MGraph Graph, Edge E )
213 {
214 /* 插入边 <V1, V2> */
215 Graph->G[E->V1][E->V2] = E->Weight;
216 /* 若是无向图,还要插入边<V2, V1> */
217 Graph->G[E->V2][E->V1] = E->Weight;
218 }
219
220 MGraph BuildGraph()
221 {
222 MGraph Graph;
223 Edge E;
224 int Nv, i;
225
226 scanf("%d", &Nv); /* 读入顶点个数 */
227 Graph = CreateGraph(Nv); /* 初始化有Nv个顶点但没有边的图 */
228
229 scanf("%d", &(Graph->Ne)); /* 读入边数 */
230 if ( Graph->Ne != 0 ) { /* 如果有边 */
231 E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */
232 /* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
233 for (i=0; i<Graph->Ne; i++) {
234 scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
235 E->V1--; E->V2--;
236 /* 注意:如果权重不是整型,Weight的读入格式要改 */
237 InsertEdge( Graph, E );
238 }
239 }
240
241
242
243 return Graph;
244 }
245
246
247
248 int main() {
249 MGraph Graph = BuildGraph();
250 int res = Prim(Graph);
251 printf("%d\n", res);
252
253 }