AcWing 1143. 联络员
克鲁斯卡尔找最小生成树,本题有一些特殊之处在于,那些必选的路径是提前算进联通块内,一个由必选路径和点构成的连通块算一个大节点,然后在这些大节点之间找最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N = 4010;
struct Edge{
int a, b, w;
bool operator< (const Edge &r) const {
return w < r.w;
}
}e[10010];
int n, m;
int res, k;
int p[N];
int find(int x){
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= n; i ++ ) p[i] = i;
for(int i = 0; i < m; i ++ ){
int q, a, b, w;
cin>>q>>a>>b>>w;
if(q == 1){
res += w;
p[find(a)] = find(b);
}
else e[k ++ ] = {a, b, w};
}
sort(e, e + k);
for(int i = 0; i < k; i ++ ){
int a = find(e[i].a), b = find(e[i].b), w = e[i].w; //需要注意这里是按边从小到大遍历,这也是克鲁斯卡尔算法的精髓所在
if(a != b){
res += w;
p[a] = b;
}
}
cout<<res<<endl;
return 0;
}