最小生成树
定义:给定一张带权无向图,G = (V, E), n = |V|, m = |E|. 由V中全部n个顶点和E中n - 1 条变构成的无向连通子图被称为G的一棵最小生成树。
算法:prime 算法 和 Kruskal算法
-
Kruskal
任意时刻, 每次选取给定的边中最短的一条边,加入到森林中,直到加完全部的边。加边过程用并查集添加。
添加最短边的方法按照边的权值从小到大排序,然后从第一个开始添加点,直到把所有的点都添加到森林中。 -
Prime
从第一个点(起点)开始,每次在所给的点中查找距离当前点最短的点,dis 数组代表距离起点的距离。然后把它们权值累加,每次选取一个点都要将dis数组更新。
最小生成树模板练习题
POJ1287
Sample Input
1 0
2 3
1 2 37
2 1 17
1 2 68
3 7
1 2 19
2 3 11
3 1 7
1 3 5
2 3 89
3 1 91
1 2 32
5 7
1 2 5
2 3 7
2 4 8
4 5 11
3 5 10
1 5 6
4 2 12
0
Sample Output
0
17
16
26
题目要求连通全部点所用的最短路径
Kruskal算法模板
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 110;
int par[N];
int rank[N];
int n, m;
struct node{
int x, y, dis;
}map[3010];
void init(int n){
for(int i = 0; i <= n; i++){
par[i] = i;
rank[i] = 0;
}
}
int find(int x){
if(par[x] == x) return x;
return par[x] = find(par[x]);
}
void unite(int x, int y){
x = find(x);
y = find(y);
if(x == y)
return ;
if(rank[x] < rank[y])
par[x] = y;
else {
par[y] = x;
if(rank[x] == rank[y])
rank[x]++;
}
return ;
}
bool cmp(node x, node y){
return x.dis < y.dis;
}
int main(){
while(scanf("%d%d", &n, &m) != EOF && n){
int cnt = 1;
init(n);
memset(map, 0, sizeof map);
int ans = 0;
for(int i = 1; i <= m; i++){
int x, y, z;
cin >> x >> y >> z;
map[i].x = x;
map[i].y = y;
map[i].dis = z;
}
sort(map + 1, map + m + 1, cmp);
for(int i = 1; i <= m; i++){
int x = find(map[i].x);
int y = find(map[i].y);
if(x != y){
cnt++;
ans += map[i].dis;
unite(map[i].x, map[i].y);
}
if(cnt >= n) break; //判断是否已经添加完所有的点
}
cout << ans << endl;
}
return 0;
}
prime算法模板
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 110;
int n;
int cost[N][N], dis[N];
bool vis[N];
char c1, c2;
int m, x, y, z;
int prime(){
for(int i = 1; i <= n; i ++ ) dis[i] = cost[1][i];
memset(vis, false, sizeof vis);
dis[1] = 0;
vis[1] = 1;
int ans = 0;
for(int i = 1; i < n; i++){
int minx = inf;
int p = -1;
for(int j = 2; j <= n; j++){
if(!vis[j] && dis[j] < minx){
minx = dis[j];
p = j;
}
}
if(p == -1) break;
vis[p] = 1;
ans += dis[p];
for(int j = 1; j <= n; j++){
if(!vis[j] && dis[j] > cost[p][j])
dis[j] = cost[p][j];
}
}
return ans;
}
int main(){
while(scanf("%d%d", &n, &m) != EOF && n){
for(int i = 0; i <= n; i++)
for(int j = 0; j <= n; j++)
if(i == j) cost[i][j] = 0;
else cost[i][j] = inf;
for(int i = 1; i <= m; i++){
int x, y, z;
cin >> x >> y >> z;
cost[x][y] = cost[y][x] = min(cost[x][y], z);
}
cout << prime() << endl;
}
return 0;
}