zoukankan      html  css  js  c++  java
  • 洛谷P4180 [Beijing2010组队]次小生成树Tree

    题目描述

    小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

    说明

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

    裸的次小生成树

    具体怎么实现一会儿整理一下挂个链接吧

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #define int long long 
    using namespace std;
    const int MAXN=400001;
    const int INF=1e15+10;
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    struct Edge
    {
        int u,v,w;
    }E[MAXN];
    int Enum=1;
    void Add(int x,int y,int z)
    {
        E[Enum].u=x;
        E[Enum].v=y;
        E[Enum].w=z;Enum++;
    }
    struct node
    {
        int u,v,w,nxt;
    }edge[MAXN];
    int head[MAXN];
    int num=1;
    int N,M;
    int fa[MAXN],vis[MAXN],sum;
    int deep[MAXN],f[MAXN][21],maxx[MAXN][21],minx[MAXN][21];
    void AddEdge(int x,int y,int z)
    {
        edge[num].u=x;
        edge[num].v=y;
        edge[num].w=z;
        edge[num].nxt=head[x];
        head[x]=num++;
    }
    int find(int x)
    {
        if(fa[x]==x) return fa[x];
        else return fa[x]=find(fa[x]);
    }
    int unionn(int x,int y)
    {
        int fx=find(x),fy=find(y);
        fa[fx]=fy;
    }
    int comp(const Edge &a,const Edge &b)
    {
        return a.w<b.w;
    }
    void Kruskal()
    {
        sort(E+1,E+Enum,comp);
        int tot=0;
        for(int i=1;i<=Enum-1;i++)
        {
            int x=E[i].u,y=E[i].v;
            if(find(x)!=find(y)) 
            {
                unionn(x,y),tot++,sum+=E[i].w,vis[i]=1;
                AddEdge(x,y,E[i].w);AddEdge(y,x,E[i].w);
            }
            if(tot==N-1) break;
        }
    }
    void dfs(int now,int fa)
    {
        for(int i=head[now];i!=-1;i=edge[i].nxt)
        {
            if(edge[i].v==fa) continue;
            deep[edge[i].v]=deep[edge[i].u]+1;
            f[edge[i].v][0]=now;
            maxx[edge[i].v][0]=edge[i].w;
            dfs(edge[i].v,now);
        }
    }
    void pre()
    {
        for(int i=1;i<=18;i++)
        {
            for(int j=1;j<=N;j++)
            {
                f[j][i]=f[ f[j][i-1] ][i-1];
                maxx[j][i]=max(maxx[j][i-1],maxx[ f[j][i-1] ][i-1]);
                minx[j][i]=max(minx[j][i-1],minx[ f[j][i-1] ][i-1]);
                if(maxx[j][i-1]>maxx[ f[j][i-1] ][i-1]) minx[j][i]=max(minx[j][i],maxx[ f[j][i-1] ][i-1]);
                else minx[j][i]=max(minx[j][i],maxx[j][i-1]);
            }
        }
    }
    int LCA(int x,int y)
    {
        if(deep[x]<deep[y]) swap(x,y);
        for(int i=18;i>=0;i--)
            if(deep[ f[x][i] ] >= deep[y] ) 
                x=f[x][i];
        if(x==y) return x;
        for(int i=18;i>=0;i--)
            if(f[x][i] != f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    int findmax(int x,int lca,int val)
    {
        int ans=0;
        for(int i=18;i>=0;i--)
        {
            if(deep[ f[x][i] ] >= deep[lca]) 
            {
                if(maxx[x][i]==val) ans=max(ans,minx[x][i]);
                else ans=max(ans,maxx[x][i]);
                x=f[x][i];
            }
        }
        return ans;
    }
    void work()
    {
        int ans=INF;
        for(int i=1;i<=Enum-1;i++)
        {
            if(vis[i]) continue;
            int x=E[i].u,y=E[i].v,z=E[i].w;
            int lca=LCA(x,y);
            int lmx=findmax(x,lca,z);
            int rmx=findmax(y,lca,z);
            if(max(lmx,rmx)!=z)
            ans=min(ans,sum+z-max(lmx,rmx));
        }
        printf("%lld",ans);
    }
    main()
    {  
        #ifdef WIN32
        freopen("a.in","r",stdin);
        #else
        #endif
        N=read(),M=read();
        memset(head,-1,sizeof(head));
        for(int i=1;i<=N;i++) fa[i]=i;
        for(int i=1;i<=M;i++)
        {
            int x=read(),y=read(),z=read();
            Add(x,y,z);
        }
        Kruskal();
        deep[1]=1;
        dfs(1,0);
        pre();
        work();
        return 0;  
    }  
  • 相关阅读:
    mysql 分库分表
    深度学习(四)转--入门深度学习的一些开源代码
    深度学习(三)转-可视化理解卷积神经网络 直接查看卷积神经网络的过程特征
    深度学习(二)神经网络中的卷积和反卷积原理
    深度学习(一)神经网络中的池化与反池化原理
    转-------基于R-CNN的物体检测
    vs2013下c++调用python脚本函数 出现的一些问题总结
    关于mfc作为上位机接收硬件端USB或串口数据显示成图片 解决串口接收数据丢字节丢包问题
    转-------CNN图像相似度匹配 2-channel network
    深度学习(五)基于tensorflow实现简单卷积神经网络Lenet5
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8457450.html
Copyright © 2011-2022 走看看