• 保留道路


    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

    50%的做法:
    先按照s升序排序。
    从小到大枚举maxg,把g小于maxg的边全部选出来,(因为前面已经排过序了),造一棵最小生成树,更新答案。时间复杂度≈O(m*m)。
    100分的做法:
    按照g升序排序。
    维护一个n-1条边的边集,是上一个建造的最小生成树的边集。
    从前往后枚举maxg,把这条边按照s用插入排序插入到当前n-1条边的集合中。
    在这样的n条边的集合中建造一颗最小生成树,最后再把用到的边存到边集中(就是将没用到的删去),从而维护了一个n-1的边集。
    刚才所说的边集其实就是维护的一棵最小生成树。
    时间复杂度≈O(m*n)。
    因为最小生成树的性质:在当前的最小生成树中插入一条边,构成了环,把环中最长的边删去就是新的最小生成树。

    60分代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cstdio>
    #include<map>
    #define LL long long
    #define N 50009
    using namespace std;
    int n,m,f[509];
    LL Ws,Wg,ans=(1ll*1<<62),order[N];
    struct H{int u,v;LL s,g;}b[N];
    LL maxg,maxs,num;
    bool cmp(H x,H y) 
    {
        return x.s<y.s;
    }
    void init()
    {
        for(int i=1;i<=n;i++) f[i]=i;
    }
    int find(int x) 
    {
        if(x==f[x])return x;
        return f[x]=find(f[x]);
    } 
    int main()
    {
        scanf("%d%d%lld%lld",&n,&m,&Wg,&Ws);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld%lld",&b[i].u,&b[i].v,&b[i].g,&b[i].s);
            b[i].s*=Ws;b[i].g*=Wg;order[i]=b[i].g;
        }
        sort(order+1,order+m+1);
        sort(b+1,b+m+1,cmp);
        for(int i=n-1;i<=m;i++)
        {
            init();
            maxg=order[i];num=n;
            for(int j=1;j<=m;j++)
            if(b[j].g<=maxg)
            {
                int fx=find(b[j].u),fy=find(b[j].v);
                if(fx!=fy)
                {
                    num--;
                    f[fx]=fy;
                    maxs=b[j].s;
                }
                if(num==1) break;
            }
            if(num==1) ans=min(ans,maxs+maxg);
        }
        if(ans==(1ll*1<<62))printf("-1
    ");
        else printf("%lld",ans);
        return 0;
    }

    100分做法:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<cstdio>
    #include<map>
    #define LL long long
    #define N 50009
    using namespace std;
    int n,m,f[509],cnt,num;
    LL ans=(1ll*1<<62);
    LL Ws,Wg,order[N],r;
    struct H{
        int u,v;
        LL s,g;
    }b[N],q[N],tree[N];
    bool used[N];
    LL maxg,maxs;
    bool cmp(H x,H y)
    {
        return x.g<y.g;
    } 
    int find(int x) 
    {
        if(x==f[x])return x;
        return f[x]=find(f[x]);
    } 
    void get_ans(LL G)
    {
        maxg=G;maxs=0;num=n;
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=cnt;i++) q[i]=tree[i],used[i]=0;
        for(int i=1;i<=cnt;i++)
        {
            int fx=find(q[i].u),fy=find(q[i].v);
            if(fx!=fy)
            {
                maxs=max(maxs,q[i].s);
                f[fx]=fy;
                num--;
                used[i]=1;
            }
        }
        if(num==1)
        {
            int p=0;
            ans=min(ans,maxs+maxg);
            for(int i=1;i<=cnt;i++)
            {
                if(used[i])
                tree[++p]=q[i];
            }
            cnt=p;
        }
    }
    int main()
    {
        scanf("%d%d%lld%lld",&n,&m,&Wg,&Ws);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld%lld",&b[i].u,&b[i].v,&b[i].g,&b[i].s);
            b[i].g*=Wg;b[i].s*=Ws;
        }
        sort(b+1,b+m+1,cmp);
    
        for(int i=1;i<=m;i++)
        {
            if(b[i].g+b[i].s>ans) continue;//这个剪枝可以减少很多多余的计算
    
            int pos=cnt+1;
            for(int j=1;j<=cnt;j++)
            if(tree[j].s>b[i].s)
            {
                pos=j;break;
            }
            if(pos==cnt+1) tree[++cnt]=b[i];
            else
            {
                ++cnt;
                for(int j=cnt;j>pos;j--)
                tree[j]=tree[j-1];
                tree[pos]=b[i];
            }
            if(cnt<n-1) continue;
            get_ans(b[i].g);
        }
        if(ans==(1ll*1<<62)) printf("-1");
        else printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    ubuntu14.04恢复系统默认中文字体
    Mcafee两个Mac版本之间的区别
    关于Windows系统防火墙
    诺顿序列号获取方法
    如何将软件限制策略发挥大作用
    BootCamp支持软件4/5
    Android系统分区理解及分区目录细解
    给Adobe Reader添加书签功能
    PHP面向对象之旅:static变量与方法
    INSERT IGNORE 与 INSERT INTO的区别
  • 原文地址:https://www.cnblogs.com/dfsac/p/7587805.html
Copyright © 2020-2023  润新知