题意:给你n,m。m条边,找出一颗最多带一个环的权值最大的子树。
思路:模仿生成树的都建方法,用并查集一条边一条边的连起来,用vis[]数组判一下,这棵树是否带环即可。代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int maxn = 100000 + 7;
int n, m, pa[maxn];
bool vis[maxn];
struct Node {
int u, v, d;
bool operator < (const Node& a) const {
return d > a.d;
}
}G[maxn];
int Find(int x) {
if(pa[x] == x) return x;
else return pa[x] = Find(pa[x]);
}
int main() {
while(~scanf("%d%d", &n, &m)) {
LL ans = 0;
if(!n && !m) break;
for(int i = 0; i <= n; ++i) pa[i] = i;
memset(vis, false, sizeof(vis));
for(int i = 0; i < m; ++i) scanf("%d%d%d", &G[i].u, &G[i].v, &G[i].d);
sort(G, G+m);
for(int i = 0; i < m; ++i) {
int x = Find(G[i].u);
int y = Find(G[i].v);
if(x != y) {
if(vis[x] && vis[y]) continue; //x和y树都带坏,不能合并
if(vis[x] || vis[y]) vis[x] = vis[y] = true; //有一个带环,则合起来,就带环
ans += G[i].d;
pa[x] = y;
}
else if(!vis[x]) { //如果没有环,则找出一条,(显然,有环的树的总权值比没有换的树的总权值要大)
vis[x] = true;
ans += G[i].d;
if(x == y) continue;
pa[x] = y;
}
}
printf("%lld\n", ans);
}
}