zoukankan      html  css  js  c++  java
  • 次小生成树

    题目描述

    小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 E_MEM ,严格次小生成树选择的边集是 E_SES ,那么需要满足:sum _{e in E_S} value(e) < sum _{e in E_M} value(e)eESvalue(e)<eEMvalue(e) 。

    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    输入格式

    第一行包含两个整数 nn 和 mm ,表示无向图的点数与边数。

    接下来 mm 行,每行3个数 x,y,zx,y,z 表示,点 xx 和点 yy 之间有一条边,边的权值为 zz 。

    输出格式

    包含一行,仅一个数,表示严格次小生成树的边权和。


    solution
    次小生成树与最小生成树一定只差一条边。
    如果差两条,我们一定可以把一条换回去。
    那么就先求出最小生成树,枚举非树边,找它在树上连成的环上的最小值替代即可。
    由于要严格次小,所以还得维护次小值,分讨即可。
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 500005
    using namespace std;
    int n,m,head[maxn],tot,fl[maxn];
    int par[maxn],deep[maxn];
    long long ans;
    struct node{
        int u,v,w,nex;
    }e[maxn*2],E[maxn];
    struct no{
        int f,m1,m2;
    }st[maxn][22];
    bool cmp(node a,node b){
        return a.w<b.w;
    }
    int getf(int k){return par[k]==k?k:par[k]=getf(par[k]);}
    void lj(int t1,int t2,int t3){
        e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
    }
    void Kruskal(){
        sort(E+1,E+m+1,cmp);
        for(int i=1;i<=n;i++)par[i]=i;
        int sum=0;
        for(int i=1;i<=m;i++){
            int f1=getf(E[i].u),f2=getf(E[i].v);
            if(f1!=f2){
                fl[i]=1;
                lj(E[i].u,E[i].v,E[i].w);
                lj(E[i].v,E[i].u,E[i].w);
                ans+=E[i].w;
                par[f1]=f2;sum++;if(sum==n-1)break;
            }
        }
    }
    void dfs(int k,int fa){
        st[k][0].f=fa;deep[k]=deep[fa]+1;
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fa){
                st[e[i].v][0].m1=e[i].w;
                dfs(e[i].v,k);
            }
        }
    }
    no merge(no A,no B){
        no C;C.f=B.f;
        C.m1=max(A.m1,B.m1);
        C.m2=max(A.m2,B.m2);
        if(A.m1<C.m1)C.m2=max(C.m2,A.m1);
        if(B.m1<C.m1)C.m2=max(C.m2,B.m1);
        return C;
    }
    no get(int v,int u){
        no A;A.m1=A.m2=0;
        if(deep[u]<deep[v])swap(u,v);
        for(int x=20;x>=0;x--){
            if(deep[st[u][x].f]>=deep[v]){
                A=merge(A,st[u][x]);
                u=st[u][x].f;
            }
        }
        for(int x=20;x>=0;x--){
            if(st[u][x].f!=st[v][x].f){
                A=merge(A,st[u][x]);A=merge(A,st[v][x]);
                u=st[u][x].f,v=st[v][x].f;
            }
        }
        if(u==v)return A;
        A=merge(A,st[u][0]);A=merge(A,st[v][0]);
        return A;
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
        }
        Kruskal();
        dfs(1,0);
        for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++){
            st[i][j]=merge(st[i][j-1],st[st[i][j-1].f][j-1]);
        }
        //for(int i=1;i<=n;i++)printf("%d %d %d
    ",st[i][1].f,st[i][1].m1,st[i][1].m2);puts("");
        int M=1e9;
        for(int i=1;i<=m;i++){
            if(fl[i])continue;
            int u=E[i].u,v=E[i].v;
            no tmp=get(u,v);
            if(tmp.m1<E[i].w)M=min(M,E[i].w-tmp.m1);
            else if(tmp.m1==E[i].w)M=min(M,E[i].w-tmp.m2);
        }
        cout<<ans+M<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    OAuth2.0协议封装类
    FFmpeg学习笔记
    mysql学习笔记(有待增补)
    使用cnpm国内淘宝镜像命令
    mongoDB中的聚合操作示例
    react的学习日常整理
    服务器防止访问超时的一些参数设置
    MongoDB基本语句操作
    CI框架配置多个数据库
    php前后台登录交互明文传输使用base64加密
  • 原文地址:https://www.cnblogs.com/liankewei/p/10646147.html
Copyright © 2011-2022 走看看