• BZOJ 1977 严格次小生成树


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

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

    输入输出格式

    输入格式:

     

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

     

    输出格式:

     

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

     

    输入输出样例

    输入样例#1:
    5 6
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6 
    输出样例#1: 
    11

    题解:严格次小生成树和非严格次小生成树的思想其实差不多,无非是多维护一个u->v之间的次大值
    然后这显然也是能用倍增维护的
    如果把最大边拆去换成新边后整棵树仍是最小生成树,那么就换次大边用,再不对就不用
    这样能保证求出的一定不是最小生成树,所以是严格次小的
    代码如下:
    #pragma GCC optimize(3)
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define mp make_pair
    #define int long long
    #define pii pair<long long,long long>
    using namespace std;
    
    struct node
    {
        int from,to,cost;
    } e[500010];
    int n,m,f[200010],ans,ans1,vis[200010],fa[19][200010],d1[19][200010],d2[19][200010],deep[200010];
    vector<pii> g[200010];
    
    int cmp(node a,node b)
    {
        return a.cost<b.cost;
    }
    
    void dfs(int now,int ff,int dep,int dis)
    {
        deep[now]=dep;
        d1[0][now]=dis;
        fa[0][now]=ff;
        for(int i=1; i<=18; i++)
        {
            fa[i][now]=fa[i-1][fa[i-1][now]];
        }
        for(int i=1; i<=18; i++)
        {
            register int a[4];
            a[0]=d1[i-1][now];
            a[1]=d1[i-1][fa[i-1][now]];
            a[2]=d2[i-1][now];
            a[3]=d2[i-1][fa[i-1][now]];
            sort(a,a+4);
            d1[i][now]=a[3];
            d2[i][now]=a[2];
        }
        for(int i=0; i<g[now].size(); i++)
        {
            if(g[now][i].first==ff) continue;
            dfs(g[now][i].first,now,dep+1,g[now][i].second);
        }
    }
    
    pii get1(int u,int v)
    {
        int di=0ll,di2=0ll;
        if(deep[u]<deep[v]) swap(u,v);
        for(int i=18; i>=0; i--)
        {
            if(deep[fa[i][u]]>=deep[v])
            {
                register int a[4];
                a[0]=di;
                a[1]=di2;
                a[2]=d1[i][u];
                a[3]=d2[i][u];
                sort(a,a+4);
                di=a[3];
                di2=a[2];
                u=fa[i][u];
            }
        }
        if(u==v) return mp(di,di2);
        for(int i=18; i>=0; i--)
        {
            if(fa[i][u]!=fa[i][v])
            {
                register int a[6];
                a[0]=di;
                a[1]=di2;
                a[2]=d1[i][u];
                a[3]=d1[i][v];
                a[4]=d2[i][u];
                a[5]=d2[i][v];
                sort(a,a+6);
                di=a[5];
                di2=a[4];
                u=fa[i][u];
                v=fa[i][v];
            }
        }
        register int a[6];
        a[0]=di;
        a[1]=di2;
        a[2]=d1[0][u];
        a[3]=d1[0][v];
        a[4]=d2[0][u];
        a[5]=d2[0][v];
        sort(a,a+6);
        di=a[5];
        di2=a[4];
        return mp(di,di2);
    }
    
    void init()
    {
        for(int i=1; i<=n; i++)
        {
            f[i]=i;
        }
    }
    
    int find(int x)
    {
        if(f[x]==x) return x;
        return f[x]=find(f[x]);
    }
    
    void unity(int i,int x,int y,int cost)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx==fy) return ;
        ans+=cost;
        f[fy]=fx;
        g[x].push_back(mp(y,cost));
        g[y].push_back(mp(x,cost));
        vis[i]=1;
    }
    
    signed main()
    {
        scanf("%lld%lld",&n,&m);
        init();
        for(int i=1; i<=m; i++)
        {
            scanf("%lld%lld%lld",&e[i].from,&e[i].to,&e[i].cost);
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1; i<=m; i++)
        {
            unity(i,e[i].from,e[i].to,e[i].cost);
        }
        dfs(1,0,0,0);
        ans1=1e16;
        for(int i=1; i<=m; i++)
        {
            if(!vis[i])
            {
                pii tmp=get1(e[i].from,e[i].to);
                int ans2=ans-tmp.first+e[i].cost;
                int ans3=ans-tmp.second+e[i].cost;
                if(ans==ans2)
                {
                    if(ans<ans3) ans1=min(ans1,ans3);
                }
                else
                {
                    ans1=min(ans1,ans2);
                }
            }
        }
        printf("%lld
    ",ans1);
    }
     
  • 相关阅读:
    hdu 刷题记录
    HDU step by step
    Codeforces Round #260 (Div. 2) B. Fedya and Maths
    Codeforces Round #260 (Div. 2) A. Laptops
    UVALive 6662 TheLastAnt
    UVALive 6661 Equal Sum Sets
    Codeforces Round #253 (Div. 2) A. Anton and Letters
    wikioi 3130 CYD刷题(背包)
    wikioi 1014 装箱问题(背包)
    [转]很特别的一个动态规划入门教程
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9336553.html
Copyright © 2020-2023  润新知