POJ-图论-最小生成树模板
Kruskal算法
1.初始时所有结点属于孤立的集合。
2.按照边权递增顺序遍历所有的边,若遍历到的边两个顶点仍分属不同的集合(该边即为连通这两个集合的边中权值最小的那条)则确定该边为最小生成树上的一条边,并将这两个顶点分属的集合合并。
3.遍历完所有边后,原图上所有结点属于同一个集合则被选取的边和原图中所有结点构成最小生成树;否则原图不连通,最小生成树不存在。
数据结构:引入边结构,并重载小于号运算符
struct Edge { int a, b;//边的两端结点编号 int cost;//边的权值 bool operator <(const Edge &A)const { return cost < A.cost;//边权从小到大排列 } }edge[6000];
用并查集来实现集合操作
void init() { for (int i = 1; i <= n; i++)p[i] = i; ans = 0; } int find(int x) { return (x == p[x]) ? x : p[x] = find(p[x]); } void Union(int i)//以边为单位合并 { int a = find(edge[i].a); int b = find(edge[i].b);//查找边的两个顶点所在集合的信息 if (a != b) //若他们属于不同集合,则选用该边 { p[b] = a;//合并集合 ans += edge[i].cost;//累加权值 } }
例 5.3 还是畅通工程
#include<cstdio> #include<algorithm> using namespace std; const int N = 101; int p[N];//父结点数组 int n;//结点数量 int ans;//最小权值和 struct Edge { int a, b;//边的两端结点编号 int cost;//边的权值 }edge[6000]; bool cmp(Edge a, Edge b) { return a.cost<b.cost; } void init() { for (int i = 1; i <= n; i++)p[i] = i; ans = 0; } int find(int x) { return (x == p[x]) ? x : p[x] = find(p[x]); } void Union(int i)//以边为单位合并 { int a = find(edge[i].a); int b = find(edge[i].b);//查找边的两个顶点所在集合的信息 if (a != b) //若他们属于不同集合,则选用该边 { p[b] = a;//合并集合 ans += edge[i].cost;//累加权值 } } int main() { while (scanf("%d", &n) != EOF && n != 0) { for (int i = 1; i <= n * (n - 1) / 2; i++) scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].cost); sort(edge + 1, edge + 1 + n * (n - 1) / 2, cmp);//起始元素为edge[1],一共n * (n - 1) / 2个待排序元素 init(); for (int i = 1; i <= n * (n - 1) / 2; i++) Union(i); printf("%d ", ans); } return 0; }
#include<cstdio> #include<algorithm> using namespace std; const int N = 101; int p[N];//父结点数组 int n;//结点数量 int ans;//最小权值和 struct Edge { int a, b;//边的两端结点编号 int cost;//边的权值 bool operator <(const Edge &A)const { return cost < A.cost;//边权从小到大排列 } }edge[6000]; void init() { for (int i = 1; i <= n; i++)p[i] = i; ans = 0; } int find(int x) { return (x == p[x]) ? x : p[x] = find(p[x]); } void Union(int i)//以边为单位合并 { int a = find(edge[i].a); int b = find(edge[i].b);//查找边的两个顶点所在集合的信息 if (a != b) //若他们属于不同集合,则选用该边 { p[b] = a;//合并集合 ans += edge[i].cost;//累加权值 } } int main() { while (scanf("%d", &n) != EOF && n != 0) { for (int i = 1; i <= n * (n - 1) / 2; i++) scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].cost); sort(edge + 1, edge + 1 + n * (n - 1) / 2);//起始元素为edge[1],一共n * (n - 1) / 2个待排序元素 init(); for (int i = 1; i <= n * (n - 1) / 2; i++) Union(i); printf("%d ", ans); } return 0; }