转载请注明来自 b0t0w1’blog
学kruskal算法时大神写的都很高端,所以写了一个最简单模板。
kruskal算法适用于边 较少情况,需要用到并查集和路径压缩。
就用百度百科的图:
答案应该是这样的:
最大路径为 39
代码如下
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
//最大结点数
#define MAX_N 100
//最大边数
#define MAX_M 4450
//储存边的信息
struct Edge{
int l; //边的结点1
int r; //边的结点2
int v; //边的权值
};
Edge edge[MAX_M];
int N,M;
//储存根节点
int father[MAX_N];
//储存某结点的轶
int son[MAX_N];
//最短路径长度
int sum = 0;
//按照边的权值排序
bool cmp (const Edge &a, const Edge &b){
return a.v < b.v;
}
/*寻找根节点,用到路径压缩。
所谓路径压缩,就是第一次寻找时直接修改了father[]数组,
直接指向根节点,而不是每次查询都要使用father[]一级一级往上跳,
而是直接跳到根节点。
*/
int findfather(int x){
if (x != father[x]){
father[x] = findfather(father[x]);
}
return father[x];
}
//将不能构成环的边的权值加入到sum中
void add(int a, int b, int v){
sum += v;
if (a == b){
return;
}
/*
根据结点轶的不同,将轶小的结点的父亲指向轶大的结点
ps:鄙人理解:
看过许多大神算法,将各两节点连接起来的方法有些不同。
这里我只是最简单的谁大谁就是根节点。
其实虽然方法不同,连接结果不同,但是kruskal算法并不关心树的具体结构,
它只关心一个点的根节点是谁即可,至于两点之间有哪些点,经过那些点不重要
*/
if (son[a] < son[b]){
father[a] = b;
son[b] += son[a];
return;
}
else{
father[b] = a;
son[a] += son[b];
return;
}
}
void kruskal(){
for (int i = 0; i < M; i++){
int a = findfather(edge[i].l);
int b = findfather(edge[i].r);
if (a != b){
add(a,b,edge[i].v);
}
}
}
int main(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
//读入点数与边数
scanf("%d%d", &N, &M);
//读入边的信息
for (int i = 0; i < M; i++){
scanf("%d%d%d", &edge[i].l, &edge[i].r, &edge[i].v);
}
//按权值排序
sort(edge, edge + M, cmp);
//初始化father[]和son[]数组
for (int i = 0; i < N; i++){
father[i] = i;
son[i] = 1;
}
kruskal();
printf ("%d", sum);
return 0;
}
输入样例:
输出样例:
ps: 还可以做改进,可以构造visit[]数组,访问过的不再访问。
转载请注明来自 b0t0w1’blog