bzoj 2406 矩阵——有源汇上下界可行流

题目: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;
}

 

posted on 2018-12-14 22:27  Narh  阅读(136)  评论(0编辑  收藏  举报

导航