[费用流] ACM-ICPC Asia China-Final Contest J. Mr.Panda and TubeMaster

%%%Manchery

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const int N=10010,inf=1<<30;

int t,n,m,cnt,S,T,SS,TT,ans,G[N],tag[N];
struct edge{
  int t,nx,w,f;
}E[N<<2];

#define x(i,j) (((i-1)*m+j)<<1)
#define y(i,j) (((i-1)*m+j)<<1|1)

inline void add(int x,int y,int f,int w){
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; E[cnt].w=w; E[cnt].f=f;
}

inline void addedge(int x,int y,int f,int w,int t){
  add(x,y,f,w); tag[cnt]=t; add(y,x,0,-w); tag[cnt]=t;
}

inline void link(int x,int y,int f,int w){
  if(w>0){
    ans+=f*w; addedge(y,x,f,-w,1); addedge(SS,y,f,0,0); addedge(x,TT,f,0,0);
  }
  else addedge(x,y,f,w,0);
}

int vis[35][35];
int dis[N],vst[N],frm[N];
queue<int> Q;

inline bool spfa(){
  for(int i=1;i<=TT;i++) dis[i]=-inf,vst[i]=0;
  vst[SS]=1; dis[SS]=0; Q.push(SS);
  while(!Q.empty()){
    int x=Q.front(); vst[x]=0; Q.pop();
    for(int i=G[x];i;i=E[i].nx)
      if(E[i].f && dis[E[i].t]<dis[x]+E[i].w){
    dis[E[i].t]=dis[x]+E[i].w; frm[E[i].t]=i;
    if(!vst[E[i].t])
      vst[E[i].t]=1,Q.push(E[i].t);
      }
  }
  if(dis[TT]==-inf) return false;
  int mf=inf;
  for(int i=TT;i!=SS;i=E[frm[i]^1].t) mf=min(mf,E[frm[i]].f);
  ans+=dis[TT]*mf;
  for(int i=TT;i!=SS;i=E[frm[i]^1].t) E[frm[i]].f-=mf,E[frm[i]^1].f+=mf;
  return true;
}

int main(){
  scanf("%d",&t); int Case=0;
  while(t--){
    memset(G,0,sizeof(G)); cnt=1; ans=0;
    scanf("%d%d",&n,&m); S=2*y(n,m)+1; T=2*y(n,m)+2; SS=T+1; TT=SS+1;
    for(int i=1;i<=n;i++)
      for(int j=1;j<m;j++){
    int c; scanf("%d",&c);
    if(~(i+j)&1)
      link(x(i,j),x(i,j+1),1,c);
    else
      link(x(i,j+1),x(i,j),1,c);
      }
    for(int i=1;i<n;i++)
      for(int j=1;j<=m;j++){
    int c; scanf("%d",&c);
    if((i+j)&1)
      link(y(i,j),y(i+1,j),1,c);
    else
      link(y(i+1,j),y(i,j),1,c);
      }
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) vis[i][j]=0;
    int e; scanf("%d",&e);
    while(e--){
      int x,y; scanf("%d%d",&x,&y); vis[x][y]=1;
    }
    int ct=0;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++){
    if((i+j)&1){
      if(!vis[i][j])
        link(x(i,j),y(i,j),1,0);
      else
        ct++,link(S,y(i,j),1,0),link(x(i,j),T,1,0);
    }
    else{
      if(!vis[i][j])
        link(y(i,j),x(i,j),1,0);
      else
        ct++,link(S,x(i,j),1,0),link(y(i,j),T,1,0);
    }
      }
    while(spfa());
    memset(G,0,sizeof(G)); int lst=cnt;
    for(int i=2;i<=lst;i++){
      if(E[i^1].t==S)
    int sss=0;
      if(E[i].t==SS || E[i].t==TT || E[i^1].t==SS || E[i^1].t==TT) continue;
      if(tag[i])
    add(E[i].t,E[i^1].t,E[i^1].f,-E[i].w);
      else
    add(E[i^1].t,E[i].t,E[i].f,E[i].w);
    }
    SS=S; TT=T;
    while(spfa()) ct--;
    if(ct) printf("Case #%d: Impossible\n",++Case);
    else printf("Case #%d: %d\n",++Case,ans);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值