1 条题解

  • 0
    @ 2025-8-24 21:41:41

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar D_14134
    AFOing。。。

    搬运于2025-08-24 21:41:40,当前版本为作者最后更新于2018-10-13 20:37:20,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    最小树形图--朱刘算法

    通过不断调整来实现最优解。

    大致思路如下:

    首先去掉自环。

    用贪心的思想给每个点选择一条最小的入边,记录连接的点。

    特判此时如果有点没有入边(除根以外),显而易见此时无解。 算上每个点入边的代价,统计答案。

    此时判定有没有有向环,如果没有直接输出。 如果有有向环,缩点,并且把连出去的边都减去连出去的点的入边,因为代价已经统计。 二次建图(或多次),对新图重复所有操作。

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=100010;
    const double inf=0x7f7f7f;
    int n,tot,m,cnt,need[maxn],pre[maxn],vis[maxn],id[maxn];
    double ans,cost[maxn],prize,inw[maxn];
    struct Edge{
        int u,v;
        double w;
    }e[maxn];
    inline void mst(){
        register int num=n,rt=1,idx;
        while(1){// 初始化
            for(register int i=1;i<=num;++i) id[i]=vis[i]=pre[i]=-1,inw[i]=inf;// 选入边
            for(register int i=1;i<=cnt;++i)
                if(inw[e[i].v]>e[i].w&&e[i].u!=e[i].v) inw[e[i].v]=e[i].w,pre[e[i].v]=e[i].u;
            pre[rt]=rt,idx=inw[rt]=0;// 缩环,统计贡献
            for(register int i=1;i<=num;++i){
                ans+=inw[i];
                if(vis[i]==-1){
                    register int nw=i;
                    while(vis[nw]==-1) vis[nw]=i,nw=pre[nw];
                    if(vis[nw]==i&&nw!=rt){
                        id[nw]=++idx;
                        for(register int j=pre[nw];j!=nw;j=pre[j]) id[j]=idx;
                    }
                }
            }// 没有环结束
            if(!idx) return; // 重标号,记录新图
            for(register int i=1;i<=num;++i) if(id[i]==-1) id[i]=++idx;
            for(register int i=1;i<=cnt;++i)
                e[i].w -=inw[e[i].v],e[i].u=id[e[i].u],e[i].v=id[e[i].v];
            num=idx,rt=id[rt];
        }
    }
    
    int main(){
        scanf("%d",&tot),n=2;
        for(register int i=1;i<=tot;++i){
            scanf("%lf%d",&cost[n],&need[n]);
            if(need[n]) e[++cnt]=(Edge){1,n,cost[n]},vis[i]=n++;
        }
        --n,scanf("%d",&m);
        for(register int i=1,a,b;i<=m;++i){
            scanf("%d%d%lf",&a,&b,&prize);
            a=vis[a],b=vis[b];
            if(a && b){
                cost[b]=min(cost[b],prize);
                e[++cnt]=(Edge){a,b,prize};
            }
        }
        for(register int i=2;i<=n;++i) ans+=(need[i]-1)*cost[i];
        mst();
        printf("%.2lf\n",ans);
        return 0;
    }
    
    • 1

    信息

    ID
    2726
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者