• bzoj千题计划158:bzoj2406: 矩阵(有源汇上下界可行流)


    http://www.lydsy.com/JudgeOnline/problem.php?id=2406

    设矩阵C=A-B

    最小化 C 一行或一列和的最大值

    整体考虑一行或者一列的和

    二分最大值

    这样每一行一列的和就有了范围

    |Σai-Σbj|<=mid

    去掉绝对值 Σai-mid <= Σbi <= Σai+mid

    构图:

    源点向行连下界为Σai-mid,上界为 Σai+mid 的边

    列向汇点连下界为Σai-mid,上界为 Σai+mid 的边

    第i行向第j列连下界为L,上界为R的边

    上下界可行流验证

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    #define N 405
    #define M 41000
    
    const int inf=2e9;
    
    int n,m,L,R;
    
    int sumh[N],suml[N];
    
    int s,t,S,T;
    
    int d[N];
    
    int SUM;
    
    int front[N],to[M<<1],nxt[M<<1],tot,val[M<<1];
    
    int lev[N],cur[N];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=0;
        //printf("%d %d %d
    ",u,v,w);
    }
    
    void build(int mid)
    {
        tot=1;
        memset(front,0,sizeof(front));
        memset(d,0,sizeof(d));
        SUM=0;
        for(int i=1;i<=n;++i) 
        {
            d[i]+=sumh[i]-mid;
            d[s]-=sumh[i]-mid;
            add(s,i,mid<<1);
        }
        for(int i=1;i<=m;++i)
        {
            d[t]+=suml[i]-mid;
            d[n+i]-=suml[i]-mid;
            add(n+i,t,mid<<1);
        }
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                d[n+j]+=L;
                d[i]-=L;
                add(i,n+j,R-L);
            }
        for(int i=1;i<=t;++i) 
        {
            if(d[i]>0) add(S,i,d[i]),SUM+=d[i];
            else if(d[i]<0) add(i,T,-d[i]);
        }
        add(t,s,inf);
    }
    
    bool bfs()
    {
        for(int i=S;i<=T;++i) lev[i]=-1,cur[i]=front[i];
        std::queue<int>q;
        q.push(S);
        lev[S]=0;
        int now;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
                if(lev[to[i]]==-1 && val[i])
                {
                    lev[to[i]]=lev[now]+1;
                    if(to[i]==T) return true;
                    q.push(to[i]);
                }
        }
        return false;
    }
    
    int dinic(int now,int flow)
    {
        if(now==T) return flow;
        int rest=0,delta;
        for(int &i=cur[now];i;i=nxt[i])
            if(lev[to[i]]==lev[now]+1 && val[i])
            {
                delta=dinic(to[i],std::min(flow-rest,val[i]));
                if(delta)
                {
                    val[i]-=delta;
                    val[i^1]+=delta;
                    rest+=delta;
                    if(rest==flow) break;
                }
            }
        if(rest!=flow) lev[now]=-1;
        return rest;
    }
    
    int maxflow()
    {
        int now=0;
        while(bfs()) now+=dinic(S,inf);
        return now;
    }
    
    bool check(int mid)
    {
        build(mid);
        return SUM==maxflow();
    }
    
    int main()
    {
        read(n); read(m);
        S=0; s=n+m+1; t=n+m+2; T=n+m+3;
        int x;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                read(x);
                sumh[i]+=x;
                suml[j]+=x;
            }
        read(L); read(R);
        int l=0,r=2e6,mid,ans=-1;
        while(l<=r)
        {
            mid=l+r>>1;
            if(check(mid)) ans=mid,r=mid-1;
            else l=mid+1;
        }
        std::cout<<ans;
    }
  • 相关阅读:
    难以捉摸?机器学习模型的可解释性初探
    什么是边缘计算?它将如何补充5G?
    2021年将会成为主流的四个云计算技术
    中国SaaS这个局,AI能破吗?
    边缘计算点燃新风暴,IT与OT之战一触即发
    为什么保护云安全是一个数学问题
    物联网中的热门IT技能
    2021 区块链及数字货币9大展望
    边缘计算将取代云计算?5G时代的最强黑马出现了吗?
    2021年区块链十大发展趋势:那些偶然中的必然
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8087160.html
Copyright © 2020-2023  润新知