【BZOJ2406】矩阵
Description
Input
第一行两个数n、m,表示矩阵的大小。
接下来n行,每行m列,描述矩阵A。
最后一行两个数L,R。
Output
第一行,输出最小的答案;
Sample Input
2 2
0 1
2 1
0 1
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