[二分 & 上下界网络流] BZOJ2406. 矩阵

来源:互联网 发布:单片机控制方案 编辑:程序博客网 时间:2024/05/17 23:06

二分答案

每一行每一列看做一个点,S向这个点连边且流量在[ΣAi,j-x,ΣAi,j+x]之间,然后行与列之间连流量在[L,R]之间的边

跑上下界网络流盼是否存在可行流就行了

#include <cstdio>#include <iostream>#include <algorithm>#include <queue>#include <cstring>using namespace std;const int N=210,inf=1<<30;int S,T,ss,tt,n,m,l,r,cnt,G[N],a[N][N],b[N],c[N];struct edge{  int t,nx,f;}E[N*N*10];inline void link(int x,int y,int f){  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; E[cnt].f=f;  E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt; E[cnt].f=0;}queue<int> Q;int dis[N],vis[N],cg[N];inline bool bfs(){  while(!Q.empty()) Q.pop();  for(int i=1;i<=T;i++) dis[i]=-1;  Q.push(S); dis[S]=0;  while(!Q.empty()){    int x=Q.front(); Q.pop();    for(int i=G[x];i;i=E[i].nx)      if(E[i].f && dis[E[i].t]==-1){    dis[E[i].t]=dis[x]+1;    if(E[i].t==T) return true;    Q.push(E[i].t);      }  }  return false;}int dfs(int x,int f){  if(x==T || !f) return f;  int used=0,w;  for(int &i=cg[x];i;i=E[i].nx)    if(E[i].f && dis[E[i].t]==dis[x]+1){      w=dfs(E[i].t,min(f-used,E[i].f));      E[i].f-=w; E[i^1].f+=w;      if((used+=w)==f) return f;    }  if(!used) dis[x]=-1;  return used;}inline bool check(int x){  cnt=1; for(int i=1;i<=T;i++) G[i]=0;  int cur=0;  for(int i=1;i<=n;i++){    if(b[i]+x<0) return false;    if(b[i]-x>0){      link(S,i,b[i]-x); link(ss,T,b[i]-x); link(ss,i,x<<1);      cur+=b[i]-x;    }    else      link(ss,i,b[i]+x);  }  for(int i=1;i<=m;i++){    if(c[i]+x<0) return false;    if(c[i]-x>0){      link(S,tt,c[i]-x); link(i+n,T,c[i]-x); link(i+n,tt,x<<1);      cur+=c[i]-x;    }    else      link(i+n,tt,c[i]+x);  }  for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++){      link(i,j+n,r);      //link(i,j+n,r-l); link(S,j+n,l); link(i,T,l);      //cur+=l;    }  link(tt,ss,inf);  while(bfs()){    for(int i=1;i<=T;i++) cg[i]=G[i];    cur-=dfs(S,inf);  }  return !cur;}int main(){  freopen("1.in","r",stdin);  freopen("1.out","w",stdout);  scanf("%d%d",&n,&m);  ss=n+m+1; tt=ss+1; S=tt+1; T=S+1;  for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)      scanf("%d",&a[i][j]);//,b[i]+=a[i][j],c[j]+=a[i][j];  scanf("%d%d",&l,&r);  for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)      a[i][j]-=l,b[i]+=a[i][j],c[j]+=a[i][j];      r-=l;  int L=0,R=200000,mid,ans;  while(L<=R)    check(mid=L+R>>1)?R=(ans=mid)-1:L=mid+1;  printf("%d\n",ans);  return 0;}
原创粉丝点击