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

【BZOJ2406】矩阵

Description

Input

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

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

最后一行两个数L,R。

Output

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

Sample Input

2 2
0 1
2 1
0 1

Sample Output

1

HINT

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

题解:容易想到二分,并且这个和式可以拆成$\sum A_{ij}-\sum B_{ij}$的形式,然后就需要你看出来这是个有上下界的网络流问题了,设二分的答案为mid,建图方法如下:

1.S->第i行 下界$\sum\limits_{j=1}^m A_{ij}$-mid,上界$\sum\limits_{j=1}^m A_{ij}$+mid
2.第j列->T 下界$\sum\limits_{i=1}^n A_{ij}$-mid,上界$\sum\limits_{i=1}^n A_{ij}$+mid
3.第i行->第j列 下界L,上界R

然后跑可行流判定即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
queue<int> q;
int n,m,ans,tot,S,T,SS,TT,L,R,cnt;
int A[210][210],sx[210],sy[210],m1[410],m2[410],to[1000010],next[1000010],val[1000010],head[410],d[410];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
}
int dfs(int x,int mf)
{
	if(x==TT)	return mf;
	int i,temp=mf,k;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(d[to[i]]==d[x]+1&&val[i])
		{
			k=dfs(to[i],min(temp,val[i]));
			if(!k)	d[to[i]]=0;
			val[i]-=k,val[i^1]+=k,temp-=k;
			if(!temp)	break;
		}
	}
	return mf-temp;
}
int bfs()
{
	while(!q.empty())	q.pop();
	memset(d,0,sizeof(d));
	q.push(SS),d[SS]=1;
	int i,u;
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i!=-1;i=next[i])
		{
			if(!d[to[i]]&&val[i])
			{
				d[to[i]]=d[u]+1;
				if(to[i]==TT)	return 1;
				q.push(to[i]);
			}
		}
	}
	return 0;
}
bool check(int x)
{
	int i,j,a,b;
	memset(head,-1,sizeof(head)),tot=ans=cnt=0;
	memset(m1,0,sizeof(m1)),memset(m2,0,sizeof(m2));
	S=n+m+1,T=S+1,SS=T+1,TT=SS+1;
	for(i=1;i<=n;i++)
	{
		a=max(sx[i]-x,0),b=sx[i]+x;
		m1[S]+=a,m2[i]+=a,add(S,i,b-a);
	}
	for(i=1;i<=m;i++)
	{
		a=max(sy[i]-x,0),b=sy[i]+x;
		m1[i+n]+=a,m2[T]+=a,add(i+n,T,b-a);
	}
	for(i=1;i<=n;i++)	for(j=1;j<=m;j++)	add(i,j+n,R-L),m1[i]+=L,m2[j+n]+=L;
	for(i=1;i<=n+m+2;i++)
	{
		if(m1[i]>m2[i])	tot+=m1[i]-m2[i],add(i,TT,m1[i]-m2[i]);
		if(m1[i]<m2[i])	add(SS,i,m2[i]-m1[i]);
	}
	add(T,S,1<<30);
	while(bfs())	ans+=dfs(SS,1<<30);
	return ans==tot;
}
int main()
{
	n=rd(),m=rd();
	int i,j,a;
	for(i=1;i<=n;i++)	for(j=1;j<=m;j++)	a=rd(),sx[i]+=a,sy[j]+=a;
	L=rd(),R=rd();
	int l=0,r=40000000,mid;
	while(l<r)
	{
		mid=(l+r)>>1;
		if(check(mid))	r=mid;
		else	l=mid+1;
	}
	printf("%d",r);
	return 0;
}//1 3 6 6 6 1 10
时间: 2025-01-02 15:36:51

【BZOJ2406】矩阵 二分+有上下界的可行流的相关文章

POJ 2396 Budget (有源汇有上下界的可行流)

POJ 2396 Budget 链接:http://poj.org/problem?id=2396 题意:给定一个M*N的矩阵,给定每行每列的和,以及其中一些值的限定条件,问能否构成一个可行的矩阵. 思路: 添加一个源点,向每行连边,每条边的上下界都为该行的和:添加一个汇点,每列向汇点连边,边的上下界都为该列的和.然后每行向每列连边,边的上下界一开始为(0,INF),之后通过一些限定条件更新. 现在问题成了求一个有源汇有上下界的可行流.只需要再添加一个超级源点,一个超级汇点,并且将原图的汇点向源

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

题意:无源无汇有上下界的可行流 模型 思路:首先将所有边的容量设为上界减去下界,然后对一个点i,设i的所有入边的下界和为to[i],所有出边的下界和为from[i],令它们的差为dif[i]=to[i]-from[i],根据流量平衡原理,让出边和入边的下界相抵消,如果dif[i]>0,说明入边把出边的下界抵消了,还剩下dif[i]的流量必须要流过来(否则不满足入边的下界条件),这时从源点向i连一条容量为dif[i]的边来表示即可,如果dif[i]<0,同理应该从i向汇点连一条容量为-dif[i

ZOJ 2314 带上下界的可行流

对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级汇,容量为x->y下界.建立有向边 x->y,容量为x->y的上界减下界. 2 从点的角度来处理. 新建超级源汇,对于每个点流进的下界和为 in, 流出此点的下界和为out.如果in > out. 建立有向边 超级源->i,容量为in-out.反之,建立有向边 i->超级汇

【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

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

弱爆了,典型的行列建模方式,居然想不到,题做少了,总结少了...... 二分答案mid s----------------------->i行----------------------->j列----------------------------->t [si-mid,si+mid]                  [L,R]                 [s[j]-mid,s[j]+mid] 即对每一行建一个点,每一列建一个点,用边来表示某一行某一列上的东西. 这种建模方式一

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

1 #include <cstdio> 2 #include <cstring> 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 #define oo 0x3f3f3f3f 5 #define N 210 6 #define M 100010 7 8 struct Dinic { 9 int n, src, dst; 10 int head[N], dest[M], flow[M], eid[M], next[M], etot; 11 int c

有上下界的最大流解法

问题模型: 给定一个加权的有向图,满足: (1)容量限制条件: (2)流量平衡条件: (2)中的即除了源汇外,所有点都满足流量平衡条件,则称G为有源汇网络:否则,即不存在源汇,所有点都满足流量平衡条件,则称G为无源汇网络. 将这类问题由易到难一一解决: 问题[1] 求无源汇的网络有上下界的可行流 由于下界是一条弧上的流必需要满足的确定值.下面引入必要弧的概念:必要弧是一定流要满的弧.必要弧的构造,将容量下界的限制分离开了,从而构造了一个没有下界的网络G': 1. 将原弧(u,v)分离出一条必要弧

zoj 3229 有源汇有上下界的最大流模板题

/*坑啊,pe的程序在zoj上原来是wa. 题目大意:一个屌丝给m个女神拍照.计划拍照n天,每一天屌丝最多个C个女神拍照,每天拍照数不能超过D张,并且给每一个女神i拍照有数量限制[Li,Ri], 对于每一个女神n天的拍照总和不能超过Gi,假设有解求屌丝最多能拍多少张照,并求每天给相应女神拍多少张照:否则输出-1. 解题思路:增设一源点st,汇点sd.st到第i天连一条上界为Di下界为0的边,每一个女神到汇点连一条下界为Gi上界为oo的边,对于每一天,当天到第i个女孩连一条[Li.Ri]的边. 建

ZOJ 3229 Shoot the Bullet(有源汇有上下界的最大流)

ZOJ 3229 Shoot the Bullet 链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3229 题意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝最多给C个女神拍照,每天拍照数不能超过D张,而且给每个女神 i 拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能超过Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 思路: 有源汇有上下界的最大流 1. 在原先