zoukankan      html  css  js  c++  java
  • 疯子的算法总结11--次小生成树+严格次小生成树

    一、总体思路

    首先,我这一题的思路是倍增LCA+Kruskal

     

    1. 首先,kruskal求最小生成树  不会的戳这里
    2. 求次小生成树 倍增  LCA

    关键在于次小生成树怎么求:

    问自己一些问题

    1. 怎么求不严格次小生成树

    2. 不严格次小生成树为什么不严格

    方法每次选择U—V之间的边,前提是最小生成树上不存在的边,添边之后删去较短边,使用LCA找到祖先,删边,这里保证次小生成树的是?只要添得边不是U-V在树上最小距离即可。

    模板

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstdio>
    typedef long long ll;
    using namespace std;
    const int M=1e5+100;
    ll n,m,res,ans=0x3f3f3f3f,mx;
    int f[M],fa[25][M],dep[M];
    ll d[2][25][M];
    bool used[3*M],vis[M];
    vector<int> a[M];
    struct Edge{
        int from, to;
        ll val;
        bool operator < (const Edge y){
            return val < y.val;
        }
    }e[3*M];
    int F(int x){
        if(f[x]==x) return x;
        return f[x]=F(f[x]);
    }
    void kruskal(){ //kruskal 算最大生成树(已保证任意两点之间最小限重最优)
        sort(e,e+m); int lef=n-1;
        for(int i=1;i<=n;++i) f[i]=i;
        for(int i=0;i<m && lef;++i){
            int x=F(e[i].from),y=F(e[i].to);
            if(x!=y){
                f[x]=y; res+=e[i].val;
                used[i]=1; --lef;
                mx=max(mx , e[i].val);
            }  
        }
    }
    void dfs(int x){    //深搜建树(可能不止一棵,因为数据未保证是连通图) 
        vis[x]=true;
        for(int i=1;i<=23;++i){
            fa[i][x]=fa[i-1][fa[i-1][x]];
            ll t1=d[0][i-1][x], t2=d[0][i-1][fa[i-1][x]];
            d[0][i][x]=max(t1 , t2);
            d[1][i][x]=max(d[1][i-1][x] , d[1][i-1][fa[i-1][x]]);
            if(t1!=t2) d[1][i][x]=max(d[1][i][x] , min(t1 , t2));
        }
        for(int i=0;i<a[x].size();++i){
            int t=e[a[x][i]].to+e[a[x][i]].from-x;
            if(vis[t]) continue;    //vis为1表示是父节点 
            dep[t]=dep[x]+1; fa[0][t]=x;
            d[0][0][t]=e[a[x][i]].val; dfs(t);
        }
    }
    int lca(int u,int v){
        if(dep[u]<dep[v])
            swap(u,v);
        if(dep[u]!=dep[v]){     //将深度做相等
            for(int i=23,h=dep[u]-dep[v];i>=0;--i)
            if(h&(1<<i)) u=fa[i][u];
        }
        if(u==v) return u;  //如果已经在一个节点上就直接返回 
        for(int i=23;i>=0;--i) if(fa[i][u]!=fa[i][v])
            u=fa[i][u] , v=fa[i][v];
        return fa[0][u];
    }
    ll get(int u,int v,int c){
        int fht=lca(u,v);
        ll m1=0,m2=0;
        for(int i=23,h1=dep[u]-dep[fht],h2=dep[v]-dep[fht];i>=0;--i){
            if(h1&(1<<i)){
                if(d[0][i][u]>m1) m2=m1,m1=d[0][i][u];
                else if(d[0][i][u]>m2) m2=d[0][i][u];
                else m2=max(m2 , d[1][i][u]);
            } if(h2&(1<<i)){
                if(d[0][i][v]>m1) m2=m1,m1=d[0][i][v];
                else if(d[0][i][v]>m2) m2=d[0][i][v];
                else m2=max(m2 , d[1][i][v]);
            }
        } if(m1==c) return c-m2;
        else return c-m1;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;++i){
            int u,v; ll w;
            scanf("%d%d%lld",&u,&v,&w);
            e[i].from=u;
            e[i].to=v;
            e[i].val=w;
        } kruskal();
        for(int i=0;i<m;++i) if(used[i]){
            a[e[i].from].push_back(i);
            a[e[i].to].push_back(i);
        } dep[1]=1; dfs(1);
        for(int i=0;i<m;++i) if(!used[i]){
            if(e[i].val-mx>ans) break;
            ll t=get(e[i].from , e[i].to , e[i].val);
            ans=min(ans , t);
        } return printf("%lld
    ",res+ans),0;
     
  • 相关阅读:
    使用.NET Core创建Windows服务(二)
    使用.NET Core创建Windows服务(一)
    在.NET Core中使用DispatchProxy“实现”非公开的接口
    ASP.NET Core 3.0中使用动态控制器路由
    从零开始实现ASP.NET Core MVC的插件式开发(五)
    微博大数据即席查询(OLAP)引擎实践
    微博数仓数据延时优化方案
    团队工作建议
    GitBook安装部署实操手册
    Wiki.js安装部署实操手册
  • 原文地址:https://www.cnblogs.com/lunatic-talent/p/12798694.html
Copyright © 2011-2022 走看看