【Hans人工解析】
①kruscal算法的第一步是给所有边按照从小到大的顺序排列;
②接下来从小到大依次考查每条边(u, v);
case1:u和v在一个连通分量中,那么加入(u, v)后会形成环,因此不能选择;
case2:如果u和v在不同的连通分量,那么加入(u, v)一定是最优的,why???【黑人问号】
【Hans人工解释】因为之前按顺序排好了边权,所以求最小生成树时越靠前的边越优呀~(感觉比某rj迷一样的反证法要清楚呢)
③关于连通分量的查询与合并;
(1)你不会告诉我你要每次用DFS或者BFS判断连通性吧?!
(2)并查集:可以把每个连通分量看成一个集合,该集合包含了连通分量的所有点,具有无序性。只要在集合中的点就同是一个父亲,这样就得到每个点只有属于或不属于的情况了。在这种情况下的查询和合并就so easy了!【查询】是否同属于一个集合=是否是一个父亲【合并】将a与b合并到一个连通分量=b的父亲赋值为a的父亲
(3)注意事项:【万分重要】并查集一定要记得路径压缩,不然效率就kk了。 怎样路径压缩呢?其实只要顺便把遍历过的节点都改成树根的子节点,下次查找就会快很多了~
【最后】感悟:夜深重写此博客,终于可以睡觉觉了(๑´ㅂ`๑)
易错:嗨呀好气啊第一次写的时候没有压缩路径,然后就尴尬了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define MAXN 10000
#define inf 999999999
int p[MAXN][MAXN],e[MAXN][MAXN],dis[MAXN],f[MAXN];
struct node{
int l, r, w;
}a[MAXN];
int find(int x){
return x == f[x] ? x : f[x] = find(f[x]);
}
int cmp(node u, node v){
return u.w < v.w;
}
int merge(int u, int v){
int f1 = find(u);
int f2 = find(v);
if(f1 != f2){
f[f1] = v;
return 1;
}
return 0;
}
int main(){
int k, m, n, sum = 0, ans = 0;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) dis[i] = inf;
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++){
e[i][i] = 0;
e[i][j] = inf;
}
for(int i = 1; i <= m; i++){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
a[i].l = x; a[i].r = y; a[i].w = z;
}
sort(a+1, a+m+1, cmp);
for(int i = 1; i <= m; i++){
if(merge(a[i].l, a[i].r)){
sum++;
ans += a[i].w;
}
if(sum == n-1) break;
}
printf("%d", ans);
return 0;
}