【bzoj2406】矩阵 二分+有上下界可行流
题目描述
输入
第一行两个数n、m,表示矩阵的大小。
接下来n行,每行m列,描述矩阵A。
最后一行两个数L,R。
输出
第一行,输出最小的答案;
样例输入
2 2
0 1
2 1
0 1
样例输出
1
题解
二分+有上下界可行流
题目一眼二分,问题转化为判断是否存在一种填数方式满足行之和的差与列之和的差都不超过mid。
然后原来的和式就可以转化为$|\sum\limits_{i=1}^na_i-\sum\limits_{i=1}^nb_i|\le mid$,即可得到$\sum\limits_{i=1}^nb_i$的范围。
对于每行和每列都得到一个这样的范围,然后这就转化为一个经典的矩阵建图模型:S向行连边,表示每行的和;行向列连边,表示每个数;列向T连边,表示每列的和。
于是就可以使用有源汇有上下界可行流来判断是否有解。
需要注意的一点是$\sum\limits_{i=1}^nb_i$的下界不能是负数,因此减的时候需要判断一下。
#include <queue>
#include <cstdio>
#include <cstring>
#define N 410
#define M 100000
#define inf 1 << 30
using namespace std;
queue<int> q;
int n , m , b , e , a[N][N] , sx[N] , sy[N] , head[N] , to[M] , val[M] , next[M] , cnt , low[N] , s , t , dis[N];
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
memset(dis , 0 , sizeof(dis));
while(!q.empty()) q.pop();
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
bool judge(int mid)
{
int i , j , tl , tr , sum = 0;
memset(head , 0 , sizeof(head)) , memset(low , 0 , sizeof(low)) , cnt = 1;
add(n + m + 1 , 0 , inf);
for(i = 1 ; i <= n ; i ++ ) tl = max(sx[i] - mid , 0) , tr = sx[i] + mid , add(0 , i , tr - tl) , low[0] -= tl , low[i] += tl;
for(i = 1 ; i <= m ; i ++ ) tl = max(sy[i] - mid , 0) , tr = sy[i] + mid , add(i + n , n + m + 1 , tr - tl) , low[i + n] -= tl , low[n + m + 1] += tl;
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
add(i , j + n , e - b) , low[i] -= b , low[j + n] += b;
for(i = 0 ; i <= n + m + 1 ; i ++ )
{
if(low[i] > 0) add(s , i , low[i]) , sum += low[i];
else add(i , t , -low[i]);
}
while(bfs()) sum -= dinic(s , inf);
return !sum;
}
int main()
{
int i , j , l = 0 , r = 200000 , mid , ans;
scanf("%d%d" , &n , &m) , s = n + m + 2 , t = n + m + 3;
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
scanf("%d" , &a[i][j]) , sx[i] += a[i][j] , sy[j] += a[i][j];
scanf("%d%d" , &b , &e);
while(l <= r)
{
mid = (l + r) >> 1;
if(judge(mid)) ans = mid , r = mid - 1;
else l = mid + 1;
}
printf("%d\n" , ans);
return 0;
}
【bzoj2406】矩阵 二分+有上下界可行流的更多相关文章
- bzoj 2406 矩阵 —— 有源汇上下界可行流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 这题,首先把题目那个式子的绝对值拆成两个限制,就成了网络流的上下界: 有上下界可行流原 ...
- bzoj 2406 矩阵——有源汇上下界可行流
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406 二分答案.把 b 的 n 个行作为一排, m 个列作为一排,每行和每列之间连上下界为 ...
- bzoj千题计划158:bzoj2406: 矩阵(有源汇上下界可行流)
http://www.lydsy.com/JudgeOnline/problem.php?id=2406 设矩阵C=A-B 最小化 C 一行或一列和的最大值 整体考虑一行或者一列的和 二分最大值 这样 ...
- BZOJ 2406 LuoguP4194 矩阵 有上下界可行流
分析: 这道题乍一看……卧槽这都什么玩意…… 然后发现给了个A矩阵,要求一个可行的B矩阵,使得矩阵C=A-B的每一行的和的绝对值和每一列的和的绝对值的最大值最小…… 好拗口啊…… 什么最大值最小之类的 ...
- poj2396 Budget(有源汇上下界可行流)
[题目链接] http://poj.org/problem?id=2396 [题意] 知道一个矩阵的行列和,且知道一些格子的限制条件,问一个可行的方案. [思路] 设行为X点,列为Y点,构图:连边(s ...
- POJ2396 Budget [有源汇上下界可行流]
POJ2396 Budget 题意:n*m的非负整数矩阵,给出每行每列的和,以及一些约束关系x,y,>=<,val,表示格子(x,y)的值与val的关系,0代表整行/列都有这个关系,求判断 ...
- 有源汇上下界可行流(POJ2396)
题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流 ...
- ZOJ1994有源汇上下界可行流
http://fastvj.rainng.com/contest/236779#problem/G Description: n 行 m 列 给你行和 与 列和 然后有Q个限制,表示特定单元格元素大小 ...
- [poj] 2396 [zoj] 1994 budget || 有源汇的上下界可行流
poj原题 zoj原题 //注意zoj最后一行不要多输出空行 现在要针对多赛区竞赛制定一个预算,该预算是一个行代表不同种类支出.列代表不同赛区支出的矩阵.组委会曾经开会讨论过各类支出的总和,以及各赛区 ...
随机推荐
- Aizu 0121 Seven Puzzle(变进制数的完美hash)
一遍预处理跑完所有情况,O(1)回答就好.状态记录我用的康拓和逆康拓. #include<bits/stdc++.h> using namespace std; ]; ]; ]; int ...
- Codeforces Round #324 (Div. 2) A B C D E
A,水题不多说. #include<bits/stdc++.h> using namespace std; //#define LOCAL int main() { #ifdef LOCA ...
- 关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)
来到个新地方,新学习C#,前面看到C#的垃圾回收,Finalize和Dispose时,总是一知半解,迷迷糊糊.这次好了,前面连续两次面试问到这个问题,脑子里不是很清晰,加上用英文来表达,更是雪上加霜的 ...
- 复习C++_指针、动态分配内存
注意:++i指的是先计算i+1,然后将其赋给i cout<<str[7]<<endl; //输出a 注:交换失败 注意:delete释放之后,变为迷途指针. 注:n--> ...
- 【思维题 最大权闭合子图】loj#6045. 「雅礼集训 2017 Day8」价
又是经典模型的好题目 题目描述 人类智慧之神 zhangzj 最近有点胖,所以要减肥,他买了 NN 种减肥药,发现每种减肥药使用了若干种药材,总共正好有 NN 种不同的药材. 经过他的人脑实验,他发现 ...
- JS - Object.create(prototype)方法
用Object.create(prototype)方法创建一个对象,这个对象的原型将指向这个传入的prototype参数
- Laravel 命令行常用命令
一.简介 1.Artisan 是 Laravel 自带的命令行接口名称,它为我们在开发过程中提供了很多有用的命令.想要查看所有可用的Artisan命令,可使用list命令: php artisan l ...
- STM32位带操作
STM32的位带操作是基于cortex内核自带的,而不是st公司独创.基本的思路就是用一个32位的地址空间访问一个bit,因为stm32只支持32位数据的读取,不像51单片机一样,是可以单独对一位操作 ...
- Cyclic Nacklace HDU - 3746 (kmp)
Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- JavaScript 计时事件-setInterval()-clearInterval() -setTimeout()-clearTimeout()
(PS:JavaScript 一个设定的时间间隔之后来执行代码,我们称之为计时事件.) JavaScript 计时事件 通过使用 JavaScript,我们有能力做到在一个设定的时间间隔之后来执行代码 ...