题意:求图的最大生成环套树森林的边权和。
一开始想的是枚举连通分量分别
。
当然这是错的,因为就算整个图连通也可以选成森林,并且后者可能比前者得到的答案要优。
但是这样要怎么维护?选择要不要连成森林的好像有点难。
考虑到
两个算法都是贪心,这个可不可以贪心地选?
从大到小,除非加一个边会让一个子图带两个环就选进去?
现在有一条边满足条件,如果它会成一个环,那就加上,把这个集合标记不能再成环。
如果不成环,那也要加上。
两种情况正确性都挺显然的。
什么样子的边满足条件?
1.不成环
2.当前未成环,成一个环
于是考虑:
1.加入当前边,不成环,是否连接两个环
2.加入当前边,成环,当前连通分量是否原来就有环
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
using namespace std;
int fa[10005], n, m, vis[10005], ans;
bool rin[10005];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y, int w) {
int fx = find(x);
int fy = find(y);
if (fx == fy) {
if (rin[fx]) return;
ans += w;
rin[fx] = 1;
return;
}
if (rin[fy] && rin[fx]) return;
fa[fx] = fy;
rin[fy] |= rin[fx];
ans += w;
}
struct sut {
int u, v, w;
bool operator < (const sut &b) const {
return w > b.w;
}
}E[100005];
int main() {
while (~scanf("%d%d", &n, &m)) {
if (!n && !m) return 0;
ans = 0;
memset(rin, 0, sizeof(rin));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i) {
fa[i] = i;
}
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
++E[i].u; ++E[i].v;
}
sort(E+1, E+1+m);
for (int i = 1; i <= m; ++i) {
merge(E[i].u, E[i].v, E[i].w);
}
printf("%d\n", ans);
}
return 0;
}
cmp函数忘记写return的应该也就我了(