zoukankan      html  css  js  c++  java
  • bzoj1977

    1977: [BeiJing2010组队]次小生成树 Tree

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 3001  Solved: 751
    [Submit][Status][Discuss]

    Description

    小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    Input

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

    Output

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

    Sample Input

    5 6
    1 2 1
    1 3 2
    2 4 3
    3 5 4
    3 4 3
    4 5 6

    Sample Output

    11

    HINT

    数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

    Source

    首先我们要知道次小生成树是最小生成树删掉一条边并加上一条边,那么枚举每条边,通过倍增计算最小边和次小边,计算答案即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> PII;
    #define N 100010
    struct edge
    {
        int to,nxt,w;
    }e[N*6];
    struct edge1 
    {
        int u,v,w;
    };
    vector<edge1> E;
    int n,m,cnt=1;
    ll tot;
    int head[N],father[N],dep[N],mark[N];
    int fa[N][23];
    ll maxcost[N][23];
    ll max(ll x,ll y)
    {
        return x>y?x:y;
    }
    ll min(ll x,ll y)
    {
        return x<y?x:y;
    }
    bool cp(edge1 x,edge1 y)
    {
        return x.w<y.w;
    }
    void link(int u,int v,int w)
    {
        e[++cnt].nxt=head[u];
        head[u]=cnt;
        e[cnt].to=v;
        e[cnt].w=w;
    }
    int find(int u)
    {
        return u==father[u]?father[u]:find(father[u]);
    }
    void connect(int u,int v)
    {
        int a=find(u);
        int b=find(v);
        if(a==b) return;
        father[a]=b;
    }
    void dfs(int u,int Fa)
    {
        for(int i=head[u];i;i=e[i].nxt) if(e[i].to!=Fa)
        {
            int v=e[i].to;
            dep[v]=dep[u]+1;
            fa[v][0]=u;
            maxcost[v][0]=e[i].w;
            dfs(v,u);
        }
    }
    PII lca(int u,int v)
    {
        PII ret;
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=22;i>=0;i--) if((dep[u]-dep[v])&(1<<i)) 
        {
            if(maxcost[u][i]>ret.first)
            {
                ret.second=ret.first;
                ret.first=maxcost[u][i];
            }
            else if(maxcost[u][i]<ret.first)
                ret.second=max(ret.second,maxcost[u][i]);
            u=fa[u][i];
        }
        if(u==v) return ret;
        for(int i=22;i>=0;i--) if(fa[u][i]!=fa[v][i]) 
        {
            if(maxcost[u][i]>ret.first)
            {
                ret.second=ret.first;
                ret.first=maxcost[u][i];
            }
            else if(maxcost[u][i]<ret.first)
                ret.second=max(ret.second,maxcost[u][i]);
            if(maxcost[v][i]>ret.first)
            {
                ret.second=ret.first;
                ret.first=maxcost[v][i];
            }
            else if(maxcost[v][i]<ret.first)
                ret.second=max(ret.second,maxcost[v][i]);
            u=fa[u][i]; v=fa[v][i];
        }
        if(maxcost[u][0]>ret.first)
        {
            ret.second=ret.first;
            ret.first=maxcost[u][0];
        }
        else if(maxcost[u][0]<ret.first)
            ret.second=max(ret.second,maxcost[u][0]);
        if(maxcost[v][0]>ret.first)
        {
            ret.second=ret.first;
            ret.first=maxcost[v][0];
        }
        else if(maxcost[v][0]<ret.first)
            ret.second=max(ret.second,maxcost[v][0]);
        return ret;
    }
    void build()
    {
        for(int i=1;i<=22;i++)
            for(int j=1;j<=n;j++) if(fa[j][i-1]!=-1)
            {
                fa[j][i]=fa[fa[j][i-1]][i-1];
                maxcost[j][i]=max(maxcost[j][i-1],
                maxcost[fa[j][i-1]][i-1]);
            }
    }
    void kruskal()
    {
        sort(E.begin(),E.end(),cp);
        for(int i=1;i<=n;i++) father[i]=i;
        for(int i=0;i<E.size();i++) if(find(E[i].u)!=find(E[i].v))
        {
            connect(E[i].u,E[i].v);
            mark[i]=1;
            tot+=E[i].w;
            link(E[i].u,E[i].v,E[i].w);
            link(E[i].v,E[i].u,E[i].w);
        }
        dfs(1,1);
        build();
        ll ans=(ll)(1e17);
        for(int i=0;i<E.size();i++) if(!mark[i])
        {
            PII x=lca(E[i].u,E[i].v);
            if(x.first<E[i].w) ans=min(ans,tot+E[i].w-x.first);
            else if(x.first==E[i].w) ans=min(ans,tot+E[i].w-x.second);
        }
        printf("%lld",ans);
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int u,v,w; scanf("%d%d%d",&u,&v,&w);
            edge1 x;
            x.u=u; x.v=v; x.w=w;
            E.push_back(x);
        }
        kruskal();
        return 0;
    }
  • 相关阅读:
    1-命令格式
    android default_workspace.xml
    多维算法思考(二):关于八皇后问题解法的探讨
    C#对excel的操作
    c#读取xml操作
    一个用 C# 实现操作 XML 文件的公共类代码
    如何使用 LINQ 执行插入、修改和删除操作
    C#--编程
    LINQ常用操作
    用线性组合表示两个数的最大公约数
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6286355.html
Copyright © 2011-2022 走看看