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
题意
给出一个图,求出最大的伪森林(伪森林就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环,并且这个子图的所有权值的和为最大)
思路
先了解一下最大生成树 什么是最大生成树?
在一个图的所有生成树中边权值和最大的生成树即为最大生成树
最大生成树算法和最小生成树的算法类似,用kruskal算法求最小生成树时,是先把边的权值从小到大排序,每次选择最小的边,再判断是否可以加入生成树
最大生成树就是将边的权值从大到小排序,每次选择最大的边,再去判断这条边是否可以加入最大生成树中即可
但是这个题没有直接用最大生成树算法,和最大生成树算法类似,稍做了一些改变,因为每个连通分量可以有一个环,所以,我们在合并两棵树时,要判断这两棵树是否有环。
如果这两棵树都有环,那么则不可以合并这两棵树,因为只允许有一个环
如果两棵树之中有一棵树有环,就可以合并,然后给没有环的那棵树做标记,表示合并之后就有环了
如果两棵树都没有环,就可以直接合并两棵树
如果有两个点是同一棵树上的,判断这棵树上是否有环,如果没有环的话,这棵树上可以有一个环,就可以将这两个点连接,建立一个环,标记有环
代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[100010],cycle[100010];
int sum;
struct node
{
int u,v,w;
} s[100010];
bool cmp(node x,node y)
{
return x.w>y.w;//从大到小排序
}
void init()
{
for(int i=0; i<100010; i++)
{
f[i]=i;
cycle[i]=0;//记录是否有环,1表示有,0表示无
}
}
int getf(int v)
{
if(f[v]==v)
return v;
else
return f[v]=getf(f[v]);
}
void kruskal()
{
int x,y;
sum=0;
for(int i=0; i<m; i++)
{
x=getf(s[i].u);
y=getf(s[i].v);
if(x!=y&&(cycle[x]!=1||cycle[y]!=1))//如果一棵树有环,可以合并
{
sum+=s[i].w;
f[x]=y;
if(cycle[x])//合并要注意标记
cycle[y]=cycle[x];
}
else if(!cycle[x])//当两个点都在一棵树上时,这棵树添加一条边构成环
{
sum+=s[i].w;
cycle[x]=1;//标记这棵树有环,1表示有环
}
}
}
int main()
{
while(cin>>n>>m)
{
init();
if(n==0&&m==0)
break;
for(int i=0; i<m; i++)
cin>>s[i].u>>s[i].v>>s[i].w;
sort(s,s+m,cmp);
kruskal();
cout<<sum<<endl;
}
return 0;
}