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\n",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;
}
时间: 2024-10-28 14:24:28

bzoj千题计划158:bzoj2406: 矩阵(有源汇上下界可行流)的相关文章

POJ2396&amp;ZOJ1994--Budget【有源汇上下界可行流】

链接:http://poj.org/problem?id=2396 题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息. 思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样. 建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一

有源汇上下界可行流(POJ2396)

题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流即可. 具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流. 然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边. 如果那些容量为l的边没满流,则无解. #include <cstdio> #incl

poj2396 Budget(有源汇上下界可行流)

[题目链接] http://poj.org/problem?id=2396 [题意] 知道一个矩阵的行列和,且知道一些格子的限制条件,问一个可行的方案. [思路] 设行为X点,列为Y点,构图:连边(s,Xi,sumXi,sumXi)(Yi,t,sumYi,sumYi)(Xi,Yj,down[i][j],up[i][j]). 则问题就是求一个有源汇点st的上下界可行流. 类似于 无源无汇上下界可行流 ,添加附加源汇点ST,边权转化为up-down,由ST向每个点连边保持流量平衡.然后添加(t,s,

算法复习——有源汇上下界可行流(bzoj2396)

题目: Description We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, so

poj2396有源汇上下界可行流

题意:给一些约束条件,要求算能否有可行流,ps:刚开始输入的是每一列和,那么就建一条上下界相同的边,这样满流的时候就一定能保证流量相同了,还有0是该列(行)对另一行每个点都要满足约束条件 解法:先按无源汇上下界可行流建边,然后添加一条从t到s的容量为inf的边,从超级源到超级汇跑一边最大流,看流量是不是等于新加边的流量和,注意这题有可能输入的数据会有锚段,那么我们需要特判一下是否有矛盾出现 还要注意的一点是:我刚开始是用string+cin读入的字符,但是出现了问题,导致我代码下面的那组数据不能

ZOJ1994有源汇上下界可行流

http://fastvj.rainng.com/contest/236779#problem/G Description: n 行 m 列 给你行和 与 列和 然后有Q个限制,表示特定单元格元素大小的范围,最后问你可行的矩阵值 Solution: 有源汇上下界最大流问题,初始源点 连 行和流量是该行对应得行和,然后列连初始汇点,容量为列的列和,详细的限制,对应于行列之间,因为我最后要输出一个矩阵,所以n * m每一条边都要链接最后,手动连一条 t s inf的边,变成无源汇有上下界可行流问题,

poj2396 Budget 有源汇上下界可行流

/** 题目:poj2396 Budget 链接:http://poj.org/problem?id=2396 题意: 给定一个n*m矩阵,矩阵元素未知.已知第1~n行的元素和,第1~m列的元素和.以及元素的一些数据范围. 求一个可行的矩阵. 思路: 联想到以前没有下届的做法,用一个s连接所有的行节点,容量为该行的和,所有的列节点连接t,容量为该列的和. 所有的行节点连接所有的列节点,容量为无穷,然后求s到t的最大流.如果从s出发的弧都是满载的,那么有解. 所有行到所有列的flow为对应的行列位

sgu176 有源汇上下界最小流

题意:有一堆点和边,1起点,n终点,某些边有可能必须满流,要求满足条件的最小流 解法:按原图建边,满流的即上下界都是容量,但是这样按有源汇上下界可行流求出来的可能不是最小流,那么我们需要开始建边的时候不要建从t到s的边,先跑一边从ss到tt的最大流,然后把该边加上再跑一次从ss到tt的最大流,那么从t到s的反向边流过的流量就是原图的最小流,为什么是这样呢,这是因为当我们第一遍跑最大流的时候,此时没有t到s的这条边,那么图中的流量会尽量按其他的边流,当我们第二次跑最大流的时候,流出来的都是第一次中

[zoj] 3229 Shoot the Bullet || 有源汇上下界最大流

zoj 文文要给幻想乡的女孩子们拍照,一共n天,m个女孩子,每天文文至多拍D[i]张照片,每个女孩子总共要被文文至少拍G[i]次.在第i天,文文可以拍c[i]个女孩子,c[i]个女孩子中每个女孩子在当天被拍的次数是[l,r],求最多可以拍多少张照片,以及每天每个可以拍的女孩子被拍了多少张照片. 有源汇上下界最大流. 先跑有源汇上下界可行流,判断是否可行,若可行则此时跑原图中s到t的最大流即为答案. //代码与题解不符-- #include<cstdio> #include<algorit