【UVA11865】比赛网络(二分+有向生成树)

该博客介绍了如何解决UVA11865比赛网络问题,采用二分查找结合最小树形图模板。在最大花费C的限制下,寻找从节点0可达所有节点的最小带宽最大值。首先通过预处理删除自环并检查可达性,然后利用朱-刘算法进行动态构建,每次迭代中处理边的冲突,最后展示了解决问题的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

    比赛网络
    题意:给出n个节点,m条有向边,每条边有花费与带宽。求解在最大花费为C的条件下构建从点0能够到达任意节点的有向图的最小带宽最大值。

I think

    二分+最小树形图模板
    很偷懒地把训练指南上的讲解piao过来……

固定根的最小树形图可以用朱-刘算法解决。首先是预处理,删除自环并判断根节点是否可以到达其他节点,如不是,输出无解终止程序。
算法主过程。首先给所有非根节点选择一条权值最小的边,若所选出的n-1条边不构成圈,则可证明构成了一个最小树形图,否则把每个圈收缩成一个点,继续上述过程。
缩圈之后,圈上所有边都消失了,因此在最终答案里需要累加上这些边权之和。但这样做有个问题:假设在某次算法的迭代中,把圈C收缩为了人工节点v,则在下一次迭代中,给v选择的入弧将与v在圈C中的入弧发生冲突。如图所示,x在圈内已经有了入弧Y–>X;若收缩之后又选了一个入弧Z–>X,必须把弧Y–>X从最小树形图中删掉。这等价于把弧Z–>X的权值减小了Y–>X的权值。

图A

果然手玩图有一种别样的美丽。。。

Code

#include<cstdio>
using namespace std;

const int sm = 1e4+5;
const int Inf = 0x3f3f3f3f;

int T,N,M,C,tot,Mx;
struct Ed {
    int u,v,w,c;
}E[sm];
struct U_Ed {
    int u,v,w;
}e[sm];

int Max(int x,int y) { return x>y?x:y; }

int In[sm],Fa[sm],V[sm],Id[sm];
bool ZhuLiu(int rt,int n,int m) {
    int ans=0;
    while(1) {
        int cnt=0;// 每一次while都需要初始化
        for(int i=1;i<=n;++i)
            In[i]=Inf,V[i]=-1,Id[i]=-1; //初始化In[i] 点i连接的最小入边 V[i] 判环
        for(int i=1;i<=m;++i)
            if(e[i].u!=e[i].v&&In[e[i].v]>e[i].w) { //迭代后可能有自环
                In[e[i].v]=e[i].w;
                Fa[e[i].v]=e[i].u;  
            }
        for(int i=1;i<=n;++i)
            if(i!=rt&&In[i]==Inf) return false; //存在多个入度为0的点
        In[rt]=0;
        for(int i=1;i<=n;++i) {
            ans+=In[i]; 
            if(ans>C) return false;
            int q=i;
            while(q!=rt&&Id[q]==-1&&V[q]!=i) //找环 遇到环停止 不可能出现环套环的情况 因此有判断条件Id[q]==-1
                V[q]=i,q=Fa[q];
            if(q!=rt&&Id[q]==-1) {
                ++cnt;
                for(int j=Fa[q];j!=q;j=Fa[j])
                    Id[j]=cnt;
                Id[q]=cnt;
            }
        }
        if(cnt==0) break;
        for(int i=1;i<=n;++i)   
            if(Id[i]==-1) Id[i]=++cnt;
        for(int i=1;i<=m;++i) {
            int a=e[i].u,b=e[i].v; 
            e[i].u=Id[a],e[i].v=Id[b];
            if(e[i].u!=e[i].v)
                e[i].w-=In[b];
        }
        n=cnt;
        rt=Id[rt];
    }
    return ans<=C;
}

bool Solve(int res) {
    tot=0;
    for(int i=1;i<=M;++i)
        if(E[i].w>=res)
            e[++tot] = (U_Ed) { E[i].u,E[i].v,E[i].c };
    return ZhuLiu(1,N,tot);
}
int main() {
    scanf("%d",&T);
    while(T--) {
        Mx=0;
        scanf("%d%d%d",&N,&M,&C);
        for(int i=1;i<=M;++i) {
            scanf("%d%d%d%d",&E[i].u,&E[i].v,&E[i].w,&E[i].c);
            if(E[i].u==E[i].v) --i,--M; 
            ++E[i].u,++E[i].v;
            Mx=Max(Mx,E[i].w);
        }
        int l=1,r=Mx,mid,Ans=0;
        while(l<=r) {
            mid=(l+r)>>1;
            if(Solve(mid)) {
                Ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        if(Ans==0) puts("streaming not possible.");
        else printf("%d kbps\n",Ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值