[费用流] ICPC 2016 China Final J. Mr.Panda and TubeMaster

传送门

dls实在是太强啦

这里写图片描述
这里写图片描述

可能是我姿势不够高
自己瞎弄弄出个 带下界带正环最大费用循环流
先加超级源汇SS和TT 去下界 转成 带正环最大费用最大流
然后再加超超级源汇S和T 跑一边最大费用最大流 消掉正环
正环没了后 再在SS和TT上跑最大费用最大流
嗯 费用流练习题

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=3005;
const int M=1000005;

struct edge{
  int u,v,w,f,next;
}G[M];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
  add(u,v,w,f,++inum),add(v,u,-w,0,++inum);
}

int S,T,SS,TT;
int dis[N],pre[N],ins[N];
int Q[10000005],l,r;
#define U G[p].u
#define V G[p].v

int Maxcost;

int clk,tag[M];

inline void Link(int u,int v,int w,int f){
  if (w<=0)
    link(u,v,w,f);
  else
    Maxcost+=w*f,link(S,v,0,f),link(u,T,0,f),link(v,u,-w,f),tag[inum]=tag[inum-1]=clk;
}

inline bool SPFA(){
  for (int i=1;i<=T;i++) dis[i]=-1<<30,pre[i]=0,ins[i]=0;
  l=r=-1; Q[++r]=S; dis[S]=0; ins[S]=1;
  while (l<r){
    int u=Q[++l]; ins[u]=0;
    for (int p=head[u];p;p=G[p].next)
      if (G[p].f && dis[V]<dis[u]+G[p].w){
    dis[V]=dis[u]+G[p].w; pre[V]=p;
    if (!ins[V]) Q[++r]=V,ins[V]=1;
      }
  }
  if (dis[T]==-1<<30) return 0;
  int minv=1<<30;
  for (int p=pre[T];p;p=pre[G[p].u])
    minv=min(minv,G[p].f);
  Maxcost+=minv*dis[T];
  for (int p=pre[T];p;p=pre[G[p].u])
    G[p].f-=minv,G[p^1].f+=minv;
  return 1;
}

int n,m;

#define I(x,y) (((x)-1)*m+(y))
#define P(x,y,z) ((2*I(x,y))-(1-(z)))

int vst[305][305];

int main(){
  int _T,K,x,y,Case=0;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(_T);
  while (_T--){
    ++clk; Maxcost=0;
    printf("Case #%d: ",++Case);
    read(n); read(m);
    SS=2*n*m+1; TT=2*n*m+2; S=2*n*m+3; T=2*n*m+4;
    for (int i=1;i<=n;i++)
      for (int j=1;j<m;j++){
    read(x);
    if ((i+j)&1)
      Link(P(i,j,0),P(i,j+1,0),x,1);
    else
      Link(P(i,j+1,0),P(i,j,0),x,1);
      }
    for (int i=1;i<n;i++)
      for (int j=1;j<=m;j++){
    read(x);
    if (~(i+j)&1)
      Link(P(i,j,1),P(i+1,j,1),x,1);
    else
      Link(P(i+1,j,1),P(i,j,1),x,1);
      }
    for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) vst[i][j]=0;
    read(K); while (K--) read(x),read(y),vst[x][y]=1;
    int cnt=0;
    for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++){
    int t=(i+j)&1;
    if (!vst[i][j])
      Link(P(i,j,t),P(i,j,t^1),0,1);
    else
      cnt++,Link(SS,P(i,j,t^1),0,1),Link(P(i,j,t),TT,0,1);
      }
    while (SPFA());
    for (int i=1;i<=T;i++) head[i]=0; int tmp=inum;

    for (int p=2;p<=tmp;p++)
      if (U!=S && U!=T && V!=S && V!=T)
    if (tag[p]!=clk)
      add(U,V,G[p].w,G[p].f,++inum);
    else{
      add(V,U,-G[p].w,G[p^1].f,++inum);
    }

    S=SS; T=TT;
    while (SPFA()) cnt--;
    if (cnt)
      printf("Impossible\n");
    else
      printf("%d\n",Maxcost);
    for (int i=1;i<=T;i++) head[i]=0; inum=1;
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值