POJ-圖論-最小生成樹模板php
Kruskal算法算法
1.初始時全部結點屬於孤立的集合。數組
2.按照邊權遞增順序遍歷全部的邊,若遍歷到的邊兩個頂點仍分屬不一樣的集合(該邊即爲連通這兩個集合的邊中權值最小的那條)則肯定該邊爲最小生成樹上的一條邊,並將這兩個頂點分屬的集合合併。數據結構
3.遍歷完全部邊後,原圖上全部結點屬於同一個集合則被選取的邊和原圖中全部結點構成最小生成樹;不然原圖不連通,最小生成樹不存在。ide
數據結構:引入邊結構,並重載小於號運算符spa
struct Edge { int a, b;//邊的兩端結點編號 int cost;//邊的權值 bool operator <(const Edge &A)const { return cost < A.cost;//邊權從小到大排列 } }edge[6000];
用並查集來實現集合操做code
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 仍是暢通工程blog
#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\n", 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\n", ans); } return 0; }