BZOJ2406矩阵
题目描述
题解
最大值最小,一眼二分没的说。
然后考虑建出这么个图,每行看做一个点,每列看做一个点,每个点看做一条连接行与列的边,源点向每行连s-mid__s+mid的边,行与列连L__R的边,列到汇连s-mid__s+mid的边。
然后判断是否有有源汇可行流。
建图时要让边权先减去下界!
代码
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define N 209 #define NN 409 #define inf 2e9 using namespace std; queue<int>q; int tot,head[NN],a[N][N],deep[NN],cur[NN],si[N],sj[N],L,R,n,m,du[NN],ans; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct edge{int n,to,l;}e[NN*NN*2]; inline void add(int u,int v,int l){ e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l; e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=0; } inline bool bfs(int s,int t){ memset(deep,0,sizeof(deep)); memcpy(cur,head,sizeof(head)); q.push(s);deep[s]=1; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!deep[v]&&e[i].l){deep[v]=deep[u]+1;q.push(v);} } } return deep[t]; } int dfs(int u,int t,int l){ if(u==t||!l)return l; int flow=0,f; for(int &i=cur[u];i;i=e[i].n){ int v=e[i].to; if(deep[v]==deep[u]+1&&(f=dfs(v,t,min(l,e[i].l)))){ e[i].l-=f;e[i^1].l+=f;l-=f;flow+=f; if(!l)break; } } return flow; } inline bool check(int mid){ int s=0,t=n+m+1,ss=m+n+2,tt=n+m+3; memset(head,0,sizeof(head));tot=1; memset(du,0,sizeof(du)); for(int i=1;i<=n;++i){ int mi=max(0,si[i]-mid); du[s]-=mi;du[i]+=mi;add(s,i,si[i]+mid-mi); } for(int i=1;i<=m;++i){ int mi=max(0,sj[i]-mid); du[n+i]-=mi;du[t]+=mi;add(i+n,t,sj[i]+mid-mi); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){du[i]-=L;du[n+j]+=L;add(i,n+j,R-L);} add(t,s,inf); for(int i=s;i<=t;++i){ if(du[i]<0)add(i,tt,-du[i]); else add(ss,i,du[i]); } while(bfs(ss,tt))dfs(ss,tt,inf); for(int i=head[ss];i;i=e[i].n)if(e[i].l)return 0; for(int i=head[tt];i;i=e[i].n)if(e[i^1].l)return 0; return 1; } int main(){ n=rd();m=rd(); for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)a[i][j]=rd(),si[i]+=a[i][j],sj[j]+=a[i][j]; L=rd();R=rd(); int l=0,r=200000; while(l<=r){ int mid=(l+r)>>1; if(check(mid))ans=mid,r=mid-1;else l=mid+1; } cout<<ans; return 0; }