1. 程式人生 > >【BZOJ2406】矩陣 二分+有上下界的可行流

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

urn ron temp mem brush 需要 大小 網絡 最小

【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

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