保留道路

来源:互联网 发布:汉聚网络怎么样 编辑:程序博客网 时间:2024/05/01 08:20

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

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 50009using 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 50009using 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;}