In graph theory, a pseudoforest is an undirected graph in which every connected component has at most one cycle. The maximal pseudoforests of G are the pseudoforest subgraphs of G that are not contained within any larger pseudoforest of G. A pesudoforest is larger than another if and only if the total value of the edges is greater than another one’s.
Input
The input consists of multiple test cases. The first line of each test case contains two integers, n(0 < n <= 10000), m(0 <= m <= 100000), which are the number of the vertexes and the number of the edges. The next m lines, each line consists of three integers, u, v, c, which means there is an edge with value c (0 < c <= 10000) between u and v. You can assume that there are no loop and no multiple edges.
The last test case is followed by a line containing two zeros, which means the end of the input.
Output
Output the sum of the value of the edges of the maximum pesudoforest.
Sample Input
3 3 0 1 1 1 2 1 2 0 1 4 5 0 1 1 1 2 1 2 3 1 3 0 1 0 2 2 0 0
Sample Output
3 5
伪森林的定义 :
- 是一个无向图;
- 它的每一个连通分量中最多只有一个环,但一个图中可以有多个不连通的连通分量。
- 伪森林的大小是它的边权的加和。
题意:给你一个无向图,求出图中最大的伪森林。
解题报告:
题意比较难懂,这道题的主要想法是最大生成树,但一开始没考虑到这个图可以是不连通的。后来,为了解决这个问题,加了一个h数组,表示以i为父节点的联通分量中有多少个环,接下来就是最大生成树的做法,不过在遇到两个已经在一个集合的点时,就判断这个集合环的数量。而两个不同集合的点合并时,还要把环的数量合并(一开始没合并错了),不过要先将环的数量求和、合并,否则的话先合并点,则两个的父节点就变成相同的了,再合并环的数量就不对了。
ac代码:
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct node{
int u,v;
int w;
void input()
{
scanf("%d%d%d",&u,&v,&w);
}
}edge[201000];
int f[20000];
int h[20000];
void init()
{
for(int i=0;i<11100;i++)
{
f[i]=i;
}
}
int getf(int v)
{
if(f[v]!=v)
f[v]=getf(f[v]);
return f[v];
}
void merge(int u,int v)
{
int t1=getf(u);
int t2=getf(v);
if(t2!=t1)
{
f[t2]=t1;
}
}
int cmp(node a,node b)
{
return a.w>b.w;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m),n+m)
{
init();
memset(h,0,sizeof(h));
for(int i=0;i<m;i++)
{
edge[i].input();
}
sort(edge,edge+m,cmp);
int ans=0,flag=1;
for(int i=0;i<m;i++)
{
if(getf(edge[i].u)!=getf(edge[i].v))
{
if(h[getf(edge[i].u)]+h[getf(edge[i].v)]<=1)
{
ans+=edge[i].w;
int tem=h[getf(edge[i].u)]+h[getf(edge[i].v)];//一开始少了这一句,两个集合合并时,要把环的数量也要一块合并。
//应该先加环数,要不父节点就改变了,再加和求出的环数就不对了。
merge(edge[i].u,edge[i].v);
h[getf(edge[i].u)]=tem;
}
}
else
{
if(h[getf(edge[i].u)]==0)
{
h[getf(edge[i].u)]=1;
ans+=edge[i].w;
// merge(edge[i].u,edge[i].v);
}
}
}
printf("%d\n",ans);
}
return 0;
}