最主要的还是并查集的使用。kruskal算法只不过是在和并集合的时候添加了条件。
#include <bits/stdc++.h>
using namespace std;
//定义的边
struct Edge {
int a;
int b;
int weight;
Edge(int _a, int _b, int _weight) {
a = _a;
b = _b;
weight = _weight;
}
};
int father[1010];
//初始化
void InitDisjointSet(int n) {
//0~n-1
for (int i = 0; i < n; ++i) {
father[i] = i;
}
}
//找爸爸
int FindDisjointset(int u) {
if (u == father[u]) {
return u;
} else {
father[u] = FindDisjointset(father[u]);
return father[u];
}
}
//合并
void UnionDisjointSet(int u, int v) {
int uroot = FindDisjointset(u);
int vroot = FindDisjointset(v);
father[vroot] = uroot;
}
//将边按权值从小到大排列
bool compare(Edge lhs, Edge rhs) {
/* sort是基于快速排序实现的,基于比较的排序。默认<。
* 重点编程:设计“compare”函数。返回值:bool;函数名:无所谓;两个参数:类型和容器元素一致。
* 当左边和右边不会发生交换时,返回真;发生交换时,返回假。*/
return lhs.weight < rhs.weight;
}
//kruskal算法的实现
int Kruskal(int n, vector<Edge> &edgeVec) {
sort(edgeVec.begin(), edgeVec.end(), compare);//将边按权值从小到大排列
//遍历edgeVec加入子图
int totalWeight = 0;//总权值
int curEdgeNum = 0;//目前的边数
for (int i = 0; i < edgeVec.size(); ++i) {
int u = edgeVec[i].a;
int v = edgeVec[i].b;
int weight = edgeVec[i].weight;
if (FindDisjointset(u) != FindDisjointset(v)) {//还未加入集合。(不属于同一个集合)
//最主要的还是并查集的使用。kruskal算法只不过是在和并集合的时候添加了条件。
UnionDisjointSet(u, v);//加入边集
++curEdgeNum;
totalWeight += weight;
if (curEdgeNum == n - 1) {//达到最大边数
//最小生成树用贪心算法恰好能得到最优解,但是不好证明。
break;
}
}
}
return totalWeight;
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
if (0 == n) {
break;
}
vector<Edge> edgeVec;//存储所有的边
InitDisjointSet(n + 1);//初始化并查集
for (int i = 0; i < (n - 1) * n / 2; ++i) {//输入数据
int u, v, weight;
scanf("%d%d%d", &u, &v, &weight);
Edge e(u, v, weight);
edgeVec.push_back(e);
}
//kruskal
printf("%d\n", Kruskal(n, edgeVec));
}
return 0;
}

京公网安备 11010502036488号