题意:给n个点,m条边,对于每输入一条边,求此时(包括前面输入的边)的最小生成树。
对于每输入一条边,以此时的边的总数作为总数来求生成树,并且,在合并的过程中要有一个删边的优化,即如果遇到一条和之前选到MST中的边之一 在同一个集合里(即有环) 那么要删除这条边,(很好理解因为之前已经挑选到了最合适的边了,所以这条边就不需要了,即2选1 只能选最优,否则就会形成环)
#include<iostream>
#include<algorithm>
#include<cstdio>
#define sf scanf
#define pf printf
#define maxn 7000
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
struct edge{
int sta,ed,w;
}E[maxn];
ll T,cnt=0,pa[maxn],n,m,Case=0;
bool cmp(edge x,edge y){
return x.w<y.w;
}
int find_set(int x){
if(x!=pa[x]){
pa[x]=find_set(pa[x]);
}
return pa[x];
}
ll Kruskal(){
ll res=0,tmp=cnt,num=0;
for(int i=0;i<=n;i++) pa[i]=i;
sort(E,E+cnt,cmp);
for(int i=0;i<tmp;i++){
int x=find_set(E[i].sta);
int y=find_set(E[i].ed);
if(x==y){
E[i]=E[cnt-1]; //这个边就是待删除边,用集合内的最后一个元素覆盖掉
cnt--;
continue;
}
num++;
pa[x]=y;
res+=E[i].w;
}
if(num!=n-1) return -1;
else return res;
}
int main(){
sf("%d",&T);
for(int Case=1;Case<=T;Case++){
pf("Case %d:\n",Case);
sf("%d%d",&n,&m);
cnt=0;
for(int j=0;j<m;j++){
sf("%d%d%d",&E[cnt].sta,&E[cnt].ed,&E[cnt].w);
cnt++;
ll ans=Kruskal();
pf("%d\n",ans);
}
}
return 0;
}