【最小生成树】IOI2003maintain

题目描述

在一个初始化为空的无向图中,不断加入新边。如果当前图连通,就求出当前图最小生成树的总权值;否则,输出-1。


分析

目前已知的算法中,破圈算法是最快的。
破圈算法顾名思义,把边按照输入顺序插入树中,如果该边的两端点在同一颗树里,再插入这条边一定会形成环。破圈算法就是把环上权值最大的边删去,就能够维持树的边权尽量小。

//破圈算法yhn(找cch要对拍程序的时候用他的号交了一遍。。)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
void Read(int &x){
    x=0;
    char c;
    bool flag=0;
    while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-');
    if(c=='-'){flag=1;c=getchar();}
    x=c-'0';
    while(c=getchar(),c!=EOF&&c>='0'&&c<='9') x=x*10+c-'0';
    if(flag==1)x=-x;
}

#define MAXN 210
#define INF 0x3FFFFFFF
using namespace std;
int fa[MAXN],f[MAXN],val[MAXN],vis[MAXN],last[MAXN];
int get_fa(int x){
    if(fa[x]==0)
        return x;
    fa[x]=get_fa(fa[x]);
    return fa[x];
}
void update(int x,int y,int stop){
    if(stop==x)
        return ;
    if(f[y]!=0)
        update(y,f[y],stop);
    val[y]=val[x];
    f[y]=x;
}
int check(int x,int y,int z){
    memset(vis,0,sizeof vis);
    int maxl=-1,maxd,k;
    int x1=x;
    while(x1!=0){
        vis[x1]=maxl;
        last[x1]=maxd;
        if(maxl<val[x1]){
            maxl=val[x1];
            maxd=x1;
        }
        x1=f[x1];
    }
    x1=y;
    maxl=0;
    while(x1!=0){
        if(vis[x1]!=0){
            if(maxl>vis[x1]){
                vis[x1]=maxl;
                last[x1]=maxd;
                k=2;
            }
            else
                k=1;
            break;
        }
        vis[x1]=maxl;
        last[x1]=maxd;
        if(maxl<val[x1]){
            maxl=val[x1];
            maxd=x1;
        }
        x1=f[x1];
    }
    if(vis[x1]>z){
        if(k==1){
            update(y,x,last[x1]);
            val[x]=z;
        }
        else{
            update(x,y,last[x1]);
            val[y]=z;
        }
    }
    return max(vis[x1],z);
}
int sum,ins,n,m,x,y,z;
int main(){
    Read(n),Read(m);
    for(int i=1;i<=m;i++){
        Read(x),Read(y),Read(z);
        int u=get_fa(x);
        int v=get_fa(y);
        if(u!=v){
            ins++;
            update(x,y,-1);
            val[y]=z;
            fa[v]=u;
            sum+=z;
        }
        else{
            int s=check(x,y,z);
            sum=sum+z-s;
        }
        if(ins<n-1)
            PF("-1\n");
        else
            PF("%d\n",sum);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值