题意:这一题题目有点绕,这里不是简单地找最大生成树,这课树还可以最多有一个环。然后我们要找出这么多树构成的最大森林。题解在代码中给出了。
代码:
/*
从大到小排序边
1、如果根结点相同,如果没有环,就合并,并标记有环。
2、如果根结点相同,有环了,就不合并。
3、如果根结点不同,如果两边多有环,就不合并。
4、如果根结点不同,两边只有一个环,那就合并,打上标记。
5、如果根节点不同,两边都没有换,就直接合并。
每次合并就根新最大时。
*/
include <bits/stdc++.h>
using namespace std;
int const N = 10000 + 10;
int const M = 100000 + 10;
int const inf = 0x7f7f7f7f;
int n,m,fa[N],vis[N];
int find(int x){
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
struct Edge
{
int u,v,w;
}p[M];
bool cmp(Edge a,Edge b){
return a.w > b.w;
}
int Kruskal(){
int ans = 0;
sort(p,p+m,cmp);
for(int i=0;i<n;i++) fa[i] = i,vis[i] = false;
for(int i=0;i<m;i++){
int x = find(p[i].u), y = find(p[i].v);
if(x == y){ //如果根结点相同,如果没有环,就合并,并标记有环。
if(!vis[y]){
fa[x] = y;
ans += p[i].w;
vis[y] = vis[x] = true;
}
}else{ //如果根结点不同,
if(vis[x]&&vis[y]) continue; //其中两个都有环,就不合并
if(vis[x]||vis[y]) vis[y] = vis[x] = true; //一个有环,打上标记合并
fa[x] = y;
ans += p[i].w;
}
}
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){ //注意不只一个连通图
if(!n && !m) return 0;
for(int i=0;i<m;i++){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
p[i] = (Edge){x,y,d};
}
printf("%d\n",Kruskal());
}
}