题目描述

输入

第一行两个数n、m,表示矩阵的大小。

接下来n行,每行m列,描述矩阵A。

最后一行两个数L,R。

输出

第一行,输出最小的答案;

样例输入

2 2
0 1
2 1
0 1

样例输出

1

提示

对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000

要求最大值最小,显然二分答案。

每次二分一个$mid$,设每行或每列的$A$之和为$VA$,$B$之和为$VB$,那么就要求每行或每列的$VA-mid\le VB\le VA+mid$,判断是否有可行解。

将源点与每行连边,流量上下界为$[VA-mid,VA+mid]$;每列与汇点连边,流量上下界为$[VA-mid,VA+mid]$;每行与每列连边,流量上下界为$[L,R]$。

每次二分跑一遍有源汇的上下界可行流判断是否满流即可。

注意$VA-mid$要与$0$取$max$。

如果输出方案的话,$b_{ij}$就是$L$加上第$i$行的点向第$j$列的点连的边的反向边流量。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int head[500];
int low[500];
int to[200010];
int val[200010];
int next[200010];
int tot=1;
int n,m;
int L,R;
int a[210][210];
int b[210][210];
int q[500];
int S,T;
int SS,TT;
int d[500];
int fx[210];
int fy[210];
int ans;
void add(int x,int y,int z)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=z;
tot++;
next[tot]=head[y];
head[y]=tot;
to[tot]=x;
val[tot]=0;
}
bool bfs(int S,int T)
{
memset(d,-1,sizeof(d));
int l=0;
int r=0;
d[S]=0;
q[r++]=S;
while(l<r)
{
int now=q[l];
l++;
for(int i=head[now];i;i=next[i])
{
if(d[to[i]]==-1&&val[i])
{
d[to[i]]=d[now]+1;
q[r++]=to[i];
}
}
}
return d[T]!=-1;
}
int dfs(int x,int maxflow)
{
if(x==TT)
{
return maxflow;
}
int used=0;
int nowflow;
for(int i=head[x];i;i=next[i])
{
if(d[to[i]]==d[x]+1&&val[i])
{
nowflow=dfs(to[i],min(val[i],maxflow-used));
val[i]-=nowflow;
val[i^1]+=nowflow;
used+=nowflow;
if(nowflow==maxflow)
{
return maxflow;
}
}
}
if(!used)
{
d[x]=-1;
}
return used;
}
int dinic()
{
int res=0;
while(bfs(SS,TT))
{
res+=dfs(SS,0x3f3f3f3f);
}
return res;
}
bool check(int lim)
{
int res=0;
tot=1;
memset(head,0,sizeof(head));
memset(low,0,sizeof(low));
add(T,S,1<<30);
int sx,sy;
for(int i=1;i<=n;i++)
{
sx=max(fx[i]-lim,0);
sy=fx[i]+lim;
add(S,i,sy-sx);
low[S]-=sx,low[i]+=sx;
}
for(int i=1;i<=m;i++)
{
sx=max(fy[i]-lim,0);
sy=fy[i]+lim;
add(n+i,T,sy-sx);
low[n+i]-=sx,low[T]+=sx;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
add(i,n+j,R-L);
low[i]-=L,low[n+j]+=L;
}
}
for(int i=1;i<=T;i++)
{
if(low[i]>0)
{
add(SS,i,low[i]);
res+=low[i];
}
else
{
add(i,TT,-low[i]);
}
}
return res==dinic();
}
int main()
{
scanf("%d%d",&n,&m);
S=n+m+1,T=S+1,SS=T+1,TT=SS+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
fx[i]+=a[i][j],fy[j]+=a[i][j];
}
}
scanf("%d%d",&L,&R);
int l=0,r=200000;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
{
ans=mid,r=mid-1;
}
else
{
l=mid+1;
}
}
printf("%d\n",ans);
// check(ans);
// for(int i=1;i<=n;i++)
// {
// for(int j=head[i];j;j=next[j])
// {
// if(to[j]>n&&to[j]<=n+m)
// {
// b[i][to[j]-n]=L+val[j^1];
// }
// }
// }
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// {
// printf("%d",b[i][j]);
// if(j!=m)
// {
// printf(" ");
// }
// }
// printf("\n");
// }
}

BZOJ2406矩阵——有上下界的可行流+二分答案的更多相关文章

  1. HDU Destroy Transportation system(有上下界的可行流)

    前几天正看着网络流,也正研究着一个有上下界的网络流的问题,查看了很多博客,觉得下面这篇概括的还是相当精确的: http://blog.csdn.net/leolin_/article/details/ ...

  2. ZOJ 2314 带上下界的可行流

    对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级 ...

  3. [ACdream 1211 Reactor Cooling]无源无汇有上下界的可行流

    题意:无源无汇有上下界的可行流 模型 思路:首先将所有边的容量设为上界减去下界,然后对一个点i,设i的所有入边的下界和为to[i],所有出边的下界和为from[i],令它们的差为dif[i]=to[i ...

  4. 【BZOJ2406】矩阵 二分+有上下界的可行流

    [BZOJ2406]矩阵 Description Input 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. Output 第一行,输出最小的答案: ...

  5. SGU 194 Reactor Cooling Dinic求解 无源无汇有上下界的可行流

    题目链接 题意:有向图中有n(1 <= n <= 200)个点,无自环或者环的节点个数至少为3.给定每条边的最小流量和最大流量,问每条边的可行流量为多少? 思路:一般求解的网络流并不考虑下 ...

  6. bzoj 2406 二分+有源有汇上下界网络流可行流判定

    弱爆了,典型的行列建模方式,居然想不到,题做少了,总结少了...... 二分答案mid s----------------------->i行-----------------------> ...

  7. sgu 194 上下界网络流可行流判定+输出可行流

    #include <cstdio> #include <cstring> #define min(a,b) ((a)<(b)?(a):(b)) #define oo 0x ...

  8. BZOJ 2406 LuoguP4194 矩阵 有上下界可行流

    分析: 这道题乍一看……卧槽这都什么玩意…… 然后发现给了个A矩阵,要求一个可行的B矩阵,使得矩阵C=A-B的每一行的和的绝对值和每一列的和的绝对值的最大值最小…… 好拗口啊…… 什么最大值最小之类的 ...

  9. zoj3229 Shoot the Bullet(有源汇有上下界的最大流)

    题意: 一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给给定的C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌 ...

随机推荐

  1. 【转载】java static 关键字的四种用法

    原文链接点这里,感谢博主分享 在java的关键字中,static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构 ...

  2. 修改phpcms中的评论样式

    phpcms中自带的评论插件很好用!但是样式个人感觉丑的狠,百度一下也没能找到解决方式,也许是自己的搜索方式不对,于是自己就研究了研究,这里可以使用两种方法进行修改 方法一: 使用PHPCMS中的ge ...

  3. PHP进程信号处理

    PHP进程信号处理 php有一组进程控制函数PCNTL,使得php能在*nix系统中实现跟c一样的创建子进程.使用exec函数执行程序.处理信号等功能. 注意:pcntl这个扩展仅在cli/cgi模式 ...

  4. easyui表格排序

    效果:点击DataGrid表格某个头部,进行升序或降序排序当前页: 问题:对应列设置  sortable:true 没有效果,刚开始以为是对应的列对应的数据库的字段类型有问题, 改动代码,使返回到前台 ...

  5. es6 proxy代理

    es6 新增构造函数 Proxy Proxy 构造函数,可以使用new 去创建,可以往里面插入两个参数,都是对象 let target = {} let handler = {} let proxy ...

  6. selenium-确认进入了预期页面

    selenium确认进入了预期页面 在自动化操作中,浏览器每次进入一个新的需要,都需要确认该页面是否打开或打开的页面是否是预期的页面 需要进行确认页面后方可进行下一步操作 确认页面有很多中方法,像每个 ...

  7. 可达用户投资额的计算(Java)

    有话要说: 前阵子遇到了一个计算可达用户投资额的问题,觉得非常有趣,故把它记录下来. 问题描述: 某产品可被投资,注册后才可以投资,其注册可以被邀请(并不是每个人都是被邀请的).邀请人可以邀请多个人注 ...

  8. Linux常用命令--文件操作

    常用Linux命令笔记(1) 1. 创建文件/文件夹 参考博客:https://www.cnblogs.com/lclq/p/5741852.html. 使用cat命令创建新文件: 输入命令 # ca ...

  9. MyDAL - .UpdateAsync() 之 .SetSegment 根据条件 动态设置 要更新的字段 使用

    索引: 目录索引 一.API 列表 1.SetSegment 属性,指示 根据条件 动态拼接 要修改的字段 见如下示例. 二.API 单表-完整 方法 举例 // update 要赋值的变量 var ...

  10. DataPipeline CTO陈肃:从ETL到ELT,AI时代数据集成的问题与解决方案

    引言:2018年7月25日,DataPipeline CTO陈肃在第一期公开课上作了题为<从ETL到ELT,AI时代数据集成的问题与解决方案>的分享,本文根据陈肃分享内容整理而成. 大家好 ...