题意可以当做求一个最大生成树,用kruscal做,而这棵树中可以包含一个环(至多一个)(用并查集做),这个时候用点数来判断kruscal是不行的,要用边数,把边排好序过滤一遍就可以了
新边只有两种情况可以加入,一个是和已生成的树的pre不同,直接加入树,另一种和树的pre相同,若此时树中无环也可以加入并且把树的cir定为1
用并查集来归并生成树的boss,就可以用cir[boss]来记录环数了
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include <math.h>
using namespace std;
#define imax 100005
int n;
long long int k;
int pre[imax],cir[imax],ans[imax];
struct list
{
int u,v,w;
}e[imax];
int cmp(list a,list b)
{
return a.w>b.w;
}
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void mix(int x,int y)
{
int r=find(x);
int l=find(y);
if(l!=r)
pre[l]=r;
}
void kruscal(int sum)
{
k=0;
int j=0;
sort(e,e+sum,cmp);
while(j<sum)
{
int l=find(e[j].u);
int r=find(e[j].v);
if(l!=r&&cir[l]+cir[r]<2)//不是同一个集合,变成同一个集合,归并环个数
{
k+=e[j].w;
//printf("%d %d %d\n",e[j].v,e[j].u,e[j].w);
mix(e[j].u,e[j].v);
if(cir[l]!=0||cir[r]!=0)
{
cir[l]=1;
cir[r]=0;
}
}
if(l==r&&cir[l]==0)//同一个集合,没有环
{
k+=e[j].w;
//printf("%d %d %d\n",e[j].v,e[j].u,e[j].w);
cir[l]=1;
}
j++;
}
}
int main()
{
int m;
while(scanf("%d %d",&n,&m),n!=0)
{
memset(cir,0,sizeof(cir));
for(int i=0;i<n;i++)
pre[i]=i;
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w);
}
kruscal(m);
cout<<k<<endl;
}
return 0;
}
/************************这道题看不懂题意,在网上看了题意,又受了些题解的启发,自己敲出来的,哎,什么时候可以直接自己写出来就好了