参考博客:https://blog.csdn.net/Shaosenmonitor/article/details/102681095
拿 HDU-1233 还是畅通工程 这道题作为例子
Description
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
Sample Output
3 5
prim算法代码
//prim(加点法) #include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <string> #include <cmath> #include <vector> #include <stack> #include <queue> #include <stack> #include <list> #include <map> #include <set> //#include <unordered_map> #define Fbo friend bool operator < (node a, node b) #define mem(a, b) memset(a, b, sizeof(a)) #define FOR(a, b, c) for (int a = b; a <= c; a++) #define RFOR(a, b, c) for (int a = b; a >= c; a--) #define off ios::sync_with_stdio(0) #define sc(a) scanf("%d",&a) bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; } using namespace std; typedef pair<int, int> pii; typedef long long ll; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const int Maxn = 1005; const double pi = acos(-1.0); const double eps = 1e-8; /* minl存储找到最小的边 minid存储最小边的节点号 sum存储最小生成树的和 */ int vis[1010];//用来标记0和1 表示这个点是否被选择过 int map1[1010][1010];//邻接矩阵用来存储图的信息 int dis[1010];//记录任意一点到这个点的最近距离 int n, m, minl, minid, sum; int prim() { mem(vis, 0); sum = 0; /*①选定1为起始点,初始化,比如从1开始,那么先把所有边的值更新到dis */ for (int i = 1; i <= n; i++){ dis[i] = map1[1][i]; } //dis[1] = 0; //vis[1] = 1;//选择起点 /*循环找最小边,循环n-1次*/ for (int i = 2; i <= n; i++)//②初始化min,minid,防止后面的用上一次数据 { minl = INF; minid = 0; //③找出当前数组最小的边,且这个节点未加入最小生成树 for (int j = 2; j <= n; j++) { if (vis[j] == 0 && dis[j] < minl)//循环找出dis的最小边的节点 { minl = dis[j]; minid = j; } } //④sum+=min,和把dis置为0,表示这个节点已经找到最小边 sum += minl; vis[minid] = 1;//表示找到了 //⑤找到最小的节点之后更新数组dis for (int j = 2; j <= n; j++)//添入新点后更新最小距离 { if (vis[j] == 0 && dis[j] > map1[minid][j])//当加入边之后,更新dis dis[j] = map1[minid][j]; } } return sum; } int main() { while (scanf("%d", &n), n)//n是点数 { int m = n * (n - 1) / 2;//m是边数 memset(map1, INF, sizeof(map1));//map1是邻接矩阵存储图的信息,初始化图 for (int i = 0; i < m; i++)//构造图 { int a, b, c; scanf("%d%d%d", &a, &b, &c); //if (c < map1[a][b])//防止重边 map1[a][b] = map1[b][a] = c; } printf("%d\n",prim()); } return 0; }
kruskal算法代码
#include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <string> #include <cmath> #include <vector> #include <stack> #include <queue> #include <stack> #include <list> #include <map> #include <set> //#include <unordered_map> #define Fbo friend bool operator < (node a, node b) #define mem(a, b) memset(a, b, sizeof(a)) #define FOR(a, b, c) for (int a = b; a <= c; a++) #define RFOR(a, b, c) for (int a = b; a >= c; a--) #define off ios::sync_with_stdio(0) #define sc(a) scanf("%d",&a) bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; } using namespace std; typedef pair<int, int> pii; typedef long long ll; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const int Maxn = 1005; const double pi = acos(-1.0); const double eps = 1e-8; int a[Maxn]; //并查集 int n, m;//点,边 struct Edge { int u, v, w; }edge[Maxn*Maxn];//定义边 bool cmp(Edge a, Edge b) { return a.w < b.w; } int find(int u) { return a[u] == u ? u : find(a[u]); //查询并查集,返回u的根节点 } int kruskal() { int ans = 0; FOR(i, 1, n) //初始化,开始每个村庄都是单独的集 a[i] = i; sort(edge + 1, edge + 1 + m, cmp);//排序后能把最短的边一次插入到图中 FOR(i, 1, m) { int b = find(edge[i].u);//边的前端点,u属于哪个集 int c = find(edge[i].v);//边的后端点,v属于哪个集 if (b == c)continue;//产生了圈,丢弃这个边 a[c]=b;//合并 ans += edge[i].w;//计算MST } return ans; } int main() { while (~scanf("%d", &n), n) { m = n * (n - 1) / 2; FOR(i, 1, m) { scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w); //两个村庄编号及距离(权值) } printf("%d\n", kruskal()); } return 0; }
原文:https://www.cnblogs.com/AlexLINS/p/12657232.html