zoukankan      html  css  js  c++  java
  • 【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行 下界$sumlimits_{j=1}^m A_{ij}$-mid,上界$sumlimits_{j=1}^m A_{ij}$+mid
    2.第j列->T 下界$sumlimits_{i=1}^n A_{ij}$-mid,上界$sumlimits_{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

     

  • 相关阅读:
    Windows Phone 31 日谈——第18日:WebBrowser控件
    Windows Phone 31 日谈——第19日:推送通知
    使用bat文件启动服务
    绝代反向指标——丘吉尔 炒股第二天就崩盘
    插入数据库返回自增长序号
    大并发服务器开发
    在这个不相信爱情的时代里,巴菲特的故事似乎让我又相信爱情了
    mysql操作语句
    马云三历高考才进大学 第一次高考数学考1分
    俞敏洪的屌丝逆袭 大学考了三次进北大
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7468762.html
Copyright © 2011-2022 走看看