• BZOJ4261 : 建设游乐场


    将图黑白染色,每个点拆成两个点,分别表示水平和竖直方向,再增加一个点以控制流量,那么每个格子都需要找两个方向去连接。

    $S$到每个黑点的控制点连边,流量$2$,费用$0$;

    控制点向两个方向的点各连两条边,第一条流量$1$,费用$0$,第二条流量$1$,费用$w$;

    然后两个方向的点分别向对应白点连边,流量$1$,费用$0$。

    这样一来如果这个格子是直轨道,那么会产生$w$的收益,如果是弯轨道,会产生$2w$的收益。

    对于白点也类似处理,求出最大费用最大流,如果满流则有解,最大收益为费用减去总收益。

    #include<cstdio>
    const int inf=~0U>>2,N=15010,M=300000,E=155;
    int n,m,i,j,tmp,flow,ans,cS,cT,a[E][E],b[E][E],id[E][E][3];
    int u[M],v[M],c[M],co[M],nxt[M],t=1,S,T,l,r,q[M],g[N],f[N],d[N];bool in[N];
    inline void add(int x,int y,int z,int zo){
      u[++t]=x;v[t]=y;c[t]=z;co[t]=zo;nxt[t]=g[x];g[x]=t;
      u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;nxt[t]=g[y];g[y]=t;
    }
    inline bool spfa(){
      int x,i;
      for(i=1;i<=T;i++)d[i]=-inf,in[i]=0;
      d[S]=0;in[S]=1;l=r=M>>1;q[l]=S;
      while(l<=r){
        x=q[l++];
        if(x==T)continue;
        for(i=g[x];i;i=nxt[i])if(c[i]&&co[i]+d[x]>d[v[i]]){
          d[v[i]]=co[i]+d[x];f[v[i]]=i;
          if(!in[v[i]]){
            in[v[i]]=1;
            if(d[v[i]]>d[q[l]])q[--l]=v[i];else q[++r]=v[i];
          }
        }
        in[x]=0;
      }
      return d[T]>-inf;
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);
      for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&b[i][j]);
      for(i=1;i<=n;i++)for(j=1;j<=m;j++){
        id[i][j][0]=++T;
        id[i][j][1]=++T;
        id[i][j][2]=++T;
      }
      T++;
      for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(!a[i][j]){
        ans-=b[i][j];
        if((i+j)&1){
          cS+=2;
          add(S,id[i][j][2],2,0);
          add(id[i][j][2],id[i][j][0],1,0);
          add(id[i][j][2],id[i][j][0],1,b[i][j]);
          add(id[i][j][2],id[i][j][1],1,0);
          add(id[i][j][2],id[i][j][1],1,b[i][j]);
          if(id[i-1][j][0])add(id[i][j][0],id[i-1][j][0],1,0);
          if(id[i+1][j][0])add(id[i][j][0],id[i+1][j][0],1,0);
          if(id[i][j-1][0])add(id[i][j][1],id[i][j-1][1],1,0);
          if(id[i][j+1][0])add(id[i][j][1],id[i][j+1][1],1,0);
        }else{
          cT+=2;
          add(id[i][j][2],T,2,0);
          add(id[i][j][0],id[i][j][2],1,0);
          add(id[i][j][0],id[i][j][2],1,b[i][j]);
          add(id[i][j][1],id[i][j][2],1,0);
          add(id[i][j][1],id[i][j][2],1,b[i][j]);
        }
      }
      if(cS!=cT)return puts("-1"),0;
      while(spfa()){
        for(tmp=inf,i=T;i!=S;i=u[f[i]])if(tmp>c[f[i]])tmp=c[f[i]];
        for(ans+=d[i=T]*tmp,flow+=tmp;i!=S;i=u[f[i]])c[f[i]]-=tmp,c[f[i]^1]+=tmp;
      }
      if(flow!=cS)return puts("-1"),0;
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    Win10远程桌面 出现 身份验证错误,要求的函数不受支持,这可能是由于CredSSP加密Oracle修正 解决方法
    通过WifI开发调试Android设备
    js 什么是深拷贝问题?
    JavaScript 如何从引用类型(Array 、 Object)创建一个新的对象
    css ::selection 的妙用
    nodejs request gb2312乱码的问题
    echarts geo地图坐标转换为页面Offset坐标
    关于 Chrome Console 查看DOM详情细节的奇思淫巧
    ie11 下 input 默认有 X 关闭按钮的问题
    办公技巧:局域网内设置固定ip
  • 原文地址:https://www.cnblogs.com/clrs97/p/6375571.html
Copyright © 2020-2023  润新知