最小树形图(朱刘算法)(+) 二分答案。
由题意得,我们要在一些有向边中选出一些边,使(0)号节点能够到达其他节点,使距离之和(leqslant cost),并且使每条边中的带宽的最小值最大。
为方便起见,我将(0 sim n-1)号节点都(++),转为(1 sim n)号节点。
第一个要求用最小树形图来解决,最小值最大用二分答案来解决,在二分时只选出带宽(geqslant mid)的边,用选出的边求最小树形图,判断二分是否合法。
多组数据以及二分答案都涉及多次进行朱刘算法,记得清空。
(code:)
#include<bits/stdc++.h>
#define maxn 20010
#define maxc 1000000
#define inf 200000000
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag) x=-x;
}
int t,p,q,c,n,m,root,l,r,ans;
struct edge
{
int x,y,v,b;
}e[maxn],ed[maxn];
int id[maxn],pre[maxn],ine[maxn],vis[maxn];
int zhuliu()
{
int tot=0,cnt;
while(1)
{
cnt=0;
for(int i=1;i<=n;++i) ine[i]=inf,id[i]=vis[i]=0;
for(int i=1;i<=m;++i)
{
int x=e[i].x,y=e[i].y,v=e[i].v;
if(x!=y&&v<ine[y]) ine[y]=v,pre[y]=x;
}
for(int i=1;i<=n;++i)
if(i!=root&&ine[i]==inf)
return -1;
for(int i=1;i<=n;++i)
{
if(i==root) continue;
tot+=ine[i];
int y=i;
while(vis[y]!=i&&!id[y]&&y!=root)
{
vis[y]=i;
y=pre[y];
}
if(!id[y]&&y!=root)
{
id[y]=++cnt;
for(int x=pre[y];x!=y;x=pre[x]) id[x]=cnt;
}
}
if(!cnt) break;
for(int i=1;i<=n;++i)
if(!id[i])
id[i]=++cnt;
for(int i=1;i<=m;++i)
{
int x=e[i].x,y=e[i].y;
e[i].x=id[x],e[i].y=id[y];
if(id[x]!=id[y]) e[i].v-=ine[y];
}
root=id[root];
n=cnt;
}
return tot;
}
bool check(int x)
{
root=1,n=p,m=0;
for(int i=1;i<=q;++i)
if(ed[i].b>=x)
e[++m]=ed[i];
int get=zhuliu();
return get!=-1&&get<=c;
}
int main()
{
read(t);
while(t--)
{
read(p),read(q),read(c);
for(int i=1;i<=q;++i)
{
read(ed[i].x),read(ed[i].y),read(ed[i].b),read(ed[i].v);
ed[i].x++,ed[i].y++;
}
l=0,r=maxc,ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
if(ans==-1) puts("streaming not possible.");
else printf("%d kbps
",ans);
}
return 0;
}