LightOJ1123 Trail Maintenance(Kruskal最小生成树,删边)

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

猜你喜欢

转载自blog.csdn.net/qq_37360631/article/details/81673330
今日推荐