ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

hdu 6982 / 2021“MINIEYE杯”中国大学生算法设计超级联赛(3)1010 Road Discount(二分+最小生成树)

2021-08-12 11:33:24  阅读:272  来源: 互联网

标签:hdu 白边 mid 生成 6982 Discount 最小 折扣价 1001


https://acm.hdu.edu.cn/showproblem.php?pid=6982

 

题意:

n个城市要修n-1条道路使他们联通,有m条道路可以修,价格有原价和折扣价

问最多可以选k个折扣价时的最小花费

对于k∈[0,n-1]依次回答

 

做这道题,得先会做“边有黑白两色,求恰好有k条白边的最小生成树”

可以看这里https://www.cnblogs.com/TheRoadToTheGold/p/15131583.html

 

这上面的基础上,题目转化为

原价就是黑边,折扣价就是白边

对于k∈[0,n-1],求“边有黑白两色,求恰好有k条白边的最小生成树”

直接枚举k用所有边求最小生成树会超时

要2个优化

 

优化一:

因为边权<=1000,提前对所有加边权的方式求解,记录使用的白边条数和总权值

这样二分的时候直接用即可

做最小生成树的次数为2000次

不提前求解的话,做最小生成树的次数为n*log(2000) 大约为10000次

 

优化二:

边数太多了

结论:在黑白两种边的最小生成树中的边,一定属于只有白边的最小生成树或者只有黑边的最小生成树

这样可以把边数优化到与n同级

因为

假设存在一条 黑白两种边的最小生成树中的边e,既不属于只有白边的最小生成树又不属于只有黑边的最小生成树

把这条边e去掉,会把树分为两部分

再去对应e的颜色中的最小生成树上,用连接这两部分的边E替换e

那么含E的最小生成树权值一定<=含e的最小生成树权值

 

#include<bits/stdc++.h>

using namespace std;

#define N 1001
#define M 400001

int n,m,mm;
struct node
{
    int u,v,w,c;
}f[M],e[N<<1];

int use,sum;

int fa[N];

int fuse[N*2+10],fsum[N*2+10];

bool cmp(node p,node q)
{
    if(p.w!=q.w) return p.w<q.w;
    return p.c<q.c;
}

int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }

void check(int x)
{
    for(int i=1;i<=m;++i) 
        if(!e[i].c) e[i].w+=x;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;++i) fa[i]=i;
    int now=0,fu,fv,j=1;
    use=sum=0;
    while(now!=n-1)
    {
        fu=find(e[j].u);
        fv=find(e[j].v);
        if(fu!=fv)
        {
            now++;
            fa[fu]=fv;
            if(!e[j].c) ++use;
            sum+=e[j].w;
        }
        ++j;
    }
    for(int i=1;i<=m;++i) 
        if(!e[i].c) e[i].w-=x;
}

void pre_edge(int col)
{
    int now=0,j=1,fu,fv;
    for(int i=1;i<=n;++i) fa[i]=i;
    sort(f+1,f+m+1,cmp);
    while(now!=n-1)
    {
        if(f[j].c==col)
        {
            fu=find(f[j].u);
            fv=find(f[j].v);
            if(fu!=fv)
            {
                now++;
                fa[fu]=fv;
                e[++mm]=f[j];
            }            
        }
        ++j;
    }
}

int main()
{
    int T;
    int l,r,mid,ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i) 
        {
            scanf("%d%d%d",&f[i*2-1].u,&f[i*2-1].v,&f[i*2-1].w);
            f[i*2-1].c=1;
            f[i*2].u=f[i*2-1].u;
            f[i*2].v=f[i*2-1].v;
            scanf("%d",&f[i*2].w);
            f[i*2].c=0;
        }
        m<<=1;
        mm=0;
        pre_edge(1);
        pre_edge(0);
        m=mm; 
        for(int k=-1001;k<=1001;++k) 
        {
            check(k);
            fsum[k+1001]=sum;
            fuse[k+1001]=use;
        }
        for(int k=0;k<n;++k)
        {
            l=-1001;
            r=1001;
            while(l<=r)
            {
                mid=l+r>>1;
                if(fuse[mid+1001]>=k) 
                {
                    ans=fsum[mid+1001]-k*mid;
                    l=mid+1;
                } 
                else r=mid-1;
            }
            printf("%d\n",ans); 
        }
    }
}

 

标签:hdu,白边,mid,生成,6982,Discount,最小,折扣价,1001
来源: https://www.cnblogs.com/TheRoadToTheGold/p/15131862.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有