题意:给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;
}