传送门
比赛网络
题意:给出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的权值。
果然手玩图有一种别样的美丽。。。
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;
}