此题是最基础的最小生成树的题目,有两种方法, 一个是prim一个是kruskal算法,前者利用邻接矩阵,后者是利用边集数组
prim算法的思想是:一个点一个点的找, 先找从第一个点到其他点最小的, 把权值存放到一个lowcost的数组中,然后继续找下一个点,然后更新lowcost数组,注意,这时的lowcost不完全是第二个点到所有点的距离,而是,其他点到最小生成树的距离,然后一步一步的求,知道求完所有点
kruskal算法的思想是:先把边集数组按照权值进行排序,之后从最小的往上找,这时有个前提,就是不能有环,这样就能保证最大连通量为1,借助father数组
代码如下:
方法一(Prim):
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int MAX = 500 + 10; 6 const int INFINITY = 999999; 7 int map[MAX][MAX]; 8 int Sum; 9 int v, e;//v来存点的个数,e来存边的个数 10 void mini_span_tree_prim() 11 { 12 int lowcost[MAX]; 13 lowcost[1] = 0;//标记已经加到最小生成树中 14 for(int i = 2; i <= v; i++) 15 { 16 lowcost[i] = map[1][i]; 17 } 18 for(int i = 2; i <= v; i++) 19 { 20 int j = 2; 21 int index = 1; 22 int minweight = INFINITY; 23 while(j <= v) 24 {//找出最小的边来,并保存其坐标 25 if(lowcost[j] != 0 && lowcost[j] < minweight) 26 { 27 minweight = lowcost[j]; 28 index = j; 29 } 30 j++; 31 } 32 lowcost[index] = 0;//标记已经加到最小生成树中 33 Sum += minweight; 34 for(j = 2; j <= v; j++) 35 {//判断没有加到最小生成树中的和比当前权值要小的点 36 if(lowcost[j] != 0 && lowcost[j] > map[index][j]) 37 { 38 lowcost[j] = map[index][j]; 39 } 40 } 41 } 42 } 43 int main() 44 { 45 //freopen("1.txt", "r", stdin); 46 int n; 47 scanf("%d", &n); 48 while(n--) 49 { 50 Sum = 0; 51 scanf("%d %d", &v, &e); 52 int t1, t2, t3; 53 memset(map, 1, sizeof(map)); 54 for(int i = 1; i <= v; i++) 55 { 56 map[i][i] = 0; 57 } 58 for(int i= 0; i < e; i++) 59 { 60 scanf("%d %d %d", &t1, &t2, &t3); 61 map[t1][t2] = t3; 62 map[t2][t1] = t3; 63 } 64 int mincost = INFINITY; 65 for(int i = 0; i < v; i++) 66 { 67 scanf("%d", &t1); 68 mincost = min(mincost, t1); 69 } 70 mini_span_tree_prim(); 71 printf("%d ", Sum + mincost); 72 } 73 return 0; 74 }
方法二(Kruskal):
#include <stdio.h> #include <algorithm> #include <cstring> using namespace std; typedef struct Node{ int s; int e; int weight; }Node; const int MAX = 500 + 10; const int INFINITY = 99999999; Node arr[MAX * 250]; int father[MAX]; int sum; int v, edges; bool cmp(Node a, Node b) { return a.weight < b.weight; } int find(int f) { while(father[f] > 0) f = father[f]; return f; } //生成最小生成树 void mini_span_tree_kruskai() { int n, m; int cnt = 0; for(int i= 0; i < edges; i++) { n = find(arr[i].s); m = find(arr[i].e); if(cnt == v - 1)//优化,如果找到了n-1条边,这时退出就行了 break; if(n != m)//判断是否构成了环 { father[m] = n; sum += arr[i].weight; cnt++; } } } int main() { int n; scanf("%d", &n); while(n--) { memset(arr, 0, sizeof(arr)); memset(father, 0, sizeof(father)); sum = 0; scanf("%d %d", &v, &edges); for(int i = 0; i < edges; ++i) { scanf("%d %d %d", &arr[i].s, &arr[i].e, &arr[i].weight); } int mincost = INFINITY; int t; for(int i = 1; i <= v; i++) { scanf("%d", &t); mincost = min(mincost, t); } sort(arr, arr + edges, cmp);//排序 // for(int i = 0; i < edges; i++) // printf("%d %d %d ", arr[i].s, arr[i].e, arr[i].weight); // printf("%d ", mincost); mini_span_tree_kruskai(); printf("%d ", sum + mincost); } return 0; }