题意:
对当前的一个图,求一个最大的伪森林,即边权值最大,每一个连通分量至多含有一个圈的森林。
分析:
类似于求一个最大生成树,先将边权值排序,之后就是一个加边合并的过程,俩点所在边可以加入到当前集合有俩个条件:
1.两点在两个集合,且有至少一个集合没有环
2.两点在一个集合,且这个集合没有环
hdu3367
#include<iostream>
#include<algorithm>
using namespace std;
struct edge
{
int u,v,c;
}e[100005];
int f[10005],n,m;
bool ee[100005],ff[10005];
__int64 total;
bool cmp(edge a,edge b)
{
return a.c>b.c;
}
void init()
{
memset(ee,false,sizeof(ee));
memset(ff,false,sizeof(ff));
for(int i=0;i<n;i++)
f[i]=i;
}
int find(int x)
{
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y,int c)
{
int a=find(x);
int b=find(y);
if(a==b) {//俩点在同一个集合,则当前若已经包含有环,则该边不可加入
if(ff[a])return ;
total+=c;
ff[a]=true;
}
else {
if(ff[a]&&ff[b]) return ;//俩点不在同一个集合,则当俩个集合都已经包含有环时,不可加入
total+=c;
f[b]=a;
if(ff[a] ||ff[b])
ff[a]=true;
}
}
int main()
{
while(scanf("%d %d",&n,&m)==2 && (n||m))
{
init();
for(int i=0;i<m;i++)
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].c);
sort(e,e+m,cmp);//将边从大到小排序
total=0;
for(int i=0;i<m;i++)
Union(e[i].u,e[i].v,e[i].c);
printf("%I64d\n",total);
}
return 0;
}