题意:给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环,
而且这个子图的所有权值之和最大。这个就是所谓的伪森林。
析:并查集,在比赛时,做了3个多小时,都没做出来,就是题意没读对,我以为就是最大生成树,但其实并不是这样的,可以不是树,是森林。。。。。
那么我们就要去想想了,先确实两个端点是不是在同一个环里,再判断是不是各自在一个环里,再判断是不是有一个在环里,然后依次做出相应的计算即可。
如果在一个环,或者是在各自环,那么就舍弃,如果有一个在环里,就标记,如果全不是而又形成环了,就标记,否则不标记。
代码如下:
#include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring> #include <set> #include <queue> #include <string> #include <algorithm> #include <vector> #include <map> using namespace std ; typedef long long LL; typedef pair<int, int> P; const int maxn = 1e4 + 5; const int INF = 0x3f3f3f3f; struct node{ int u, v, c; node(int uu = 0, int vv = 0, int cc = 0) : u(uu), v(vv), c(cc) { } bool operator < (const node &p) const{ return c > p.c; } }; node a[maxn*10]; int p[maxn]; int vis[maxn]; int Find(int x){ return x == p[x] ? x : p[x] = Find(p[x]); } int main(){ int n, m; while(scanf("%d %d", &n, &m)){ if(!m && !n) break; memset(vis, 0, sizeof(vis)); for(int i = 1; i <= n; ++i) p[i] = i; for(int i = 0; i < m; ++i){ int u, v, c; scanf("%d %d %d", &u, &v, &c); a[i] = node(u+1, v+1, c); } sort(a, a+m); int ans = 0; for(int i = 0; i < m; ++i){ int x = Find(a[i].u); int y = Find(a[i].v); if(x == y){ if(!vis[x] && !vis[y]){ ans += a[i].c; vis[x] = vis[y] = 1; p[y] = x; } } else{ if(!vis[x] && !vis[y]){ ans += a[i].c; p[y] = x; } else if(!vis[x] || !vis[y]){ ans += a[i].c; vis[x] = vis[y] = 1; p[y] = x; } } } cout << ans << endl; } return 0; }