[HDU3367] Pseudoforest [最大生成環套樹森林][並查集]
阿新 • • 發佈:2018-11-12
題意:求圖的最大生成環套樹森林的邊權和。
一開始想的是列舉連通分量分別
。
當然這是錯的,因為就算整個圖連通也可以選成森林,並且後者可能比前者得到的答案要優。
但是這樣要怎麼維護?選擇要不要連成森林的好像有點難。
考慮到
兩個演算法都是貪心,這個可不可以貪心地選?
從大到小,除非加一個邊會讓一個子圖帶兩個環就選進去?
現在有一條邊滿足條件,如果它會成一個環,那就加上,把這個集合標記不能再成環。
如果不成環,那也要加上。
兩種情況正確性都挺顯然的。
什麼樣子的邊滿足條件?
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的應該也就我了(