题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2406
二分答案。把 b 的 n 个行作为一排, m 个列作为一排,每行和每列之间连上下界为 L , R 的边,源点向每行连以 “ a 的该行的值的和” 加/减 mid 为上下界的边,每列向汇点连以 “ a 的该列的值的和” 加/减 mid 为上下界的边;然后跑可行流就行了。
自己把和超级源点及超级汇点的无关的边先连好了,到时候改一改容量就行了。但别忘了把 hd[ ] , cap[ ] , xnt , tp[ ] 都赋回原来的值。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=205,M=N*N<<1,INF=4e7+5; int n,m,yhd[N<<1],hd[N<<1],xnt=1,cur[N<<1],bj,to[M],nxt[M],ycap[M],cap[M],dy[N<<1]; int sh[N],sl[N],s,t,ss,tt,tp[N<<1],ttp[N<<1]; int dfn[N<<1],q[N<<1],he,tl; int Mn(int a,int b){return a<b?a:b;} int Mx(int a,int b){return a>b?a:b;} int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } void add(int x,int y,int z) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=z; to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0; } bool bfs(int mid) { memset(dfn,0,sizeof dfn);dfn[ss]=1; q[he=tl=1]=ss; while(he<=tl) { int k=q[he++]; for(int i=hd[k],v;i;i=nxt[i]) if(!dfn[v=to[i]]&&cap[i]) dfn[v]=dfn[k]+1,q[++tl]=v; } return dfn[tt]; } int dinic(int cr,int flow) { if(cr==tt)return flow; int use=0; for(int& i=cur[cr],v;i;i=nxt[i]) if(dfn[v=to[i]]==dfn[cr]+1&&cap[i]) { int tmp=dinic(v,Mn(flow-use,cap[i])); if(!tmp)dfn[v]=0; use+=tmp;cap[i]-=tmp;cap[i^1]+=tmp; if(use==flow)return use; } return use; } bool chk(int mid) { xnt=bj;memcpy(ttp,tp,sizeof tp); memcpy(hd,yhd,sizeof yhd);// for(int i=2;i<=bj;i++)cap[i]=ycap[i];/// for(int i=1;i<=n;i++) { int l=Mx(sh[i]-mid,0),r=sh[i]+mid; cap[dy[i]]=r-l;cap[dy[i]^1]=0; ttp[i]+=l;ttp[s]-=l; } for(int i=1;i<=m;i++) { int l=Mx(sl[i]-mid,0),r=sl[i]+mid; cap[dy[i+n]]=r-l;cap[dy[i+n]^1]=0; ttp[i+n]-=l;ttp[t]+=l; } int val=0; for(int i=0;i<=t;i++) if(ttp[i]>0)add(ss,i,ttp[i]),val+=ttp[i]; else if(ttp[i]<0)add(i,tt,-ttp[i]); while(bfs(mid)) memcpy(cur,hd,sizeof hd),val-=dinic(ss,INF); return !val; } int main() { n=rdn();m=rdn(); for(int i=1,d;i<=n;i++) for(int j=1;j<=m;j++) d=rdn(),sh[i]+=d,sl[j]+=d; int L=rdn(),R=rdn(); s=0;t=n+m+1; ss=n+m+2;tt=n+m+3; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) add(i,j+n,R-L),tp[i]-=L,tp[j+n]+=L; add(t,s,INF); for(int i=1;i<=n;i++) add(s,i,0),dy[i]=xnt-1; for(int i=n+1,j=n+m;i<=j;i++) add(i,t,0),dy[i]=xnt-1; bj=xnt; memcpy(yhd,hd,sizeof hd); for(int i=2;i<=bj;i++)ycap[i]=cap[i]; int l=0,r=2e5+5,ans; while(l<=r) { int mid=l+r>>1; if(chk(mid))ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); return 0; }