题解 UVA11865 【Stream My Contest】

最小树形图(朱刘算法)\(+\) 二分答案。

由题意得,我们要在一些有向边中选出一些边,使\(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\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lhm-/p/12229854.html