Fork me on GitHub

保留道路

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

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\n");
    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;
}
posted @   primes  阅读(114)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示