p3159 [CQOI2012]交换棋子

传送门

分析

https://www.luogu.org/blog/dedicatus545/solution-p3159

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m,le[10010],ri[10010],now[10010],v[10010],beg[10010],end[10010];
int s,t,Ans,sum1,sum2;
int head[100100],w[100100],c[100100],nxt[100100],to[100100];
int ano[100100],fm[100100],cnt;
inline void add(int x,int y,int cost,int z){
    nxt[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;c[cnt]=cost;fm[cnt]=x;
    nxt[++cnt]=head[y];head[y]=cnt;to[cnt]=x;w[cnt]=0;c[cnt]=-cost;fm[cnt]=y;
    ano[cnt]=cnt-1;ano[cnt-1]=cnt;
}
inline void g(int id,int x,int y){
    if(x<1||y<1||x>n||y>m)return;
    add(ri[id],le[(x-1)*m+y],0,inf);
}
inline void goadd(int i){
    int x=i/m+1,y=i%m;
    if(y==0)x--,y=m;
    g(i,x-1,y-1),g(i,x-1,y),g(i,x-1,y+1);
    g(i,x,y-1),g(i,x,y+1);
    g(i,x+1,y-1),g(i,x+1,y),g(i,x+1,y+1);    
}
queue<int>q;
int iq[100100],d[100100],la[100100],nf[100100];
inline void work(){
    while(1){
      memset(d,0x3f,sizeof(d));
      d[s]=0;q.push(s);iq[s]=1;
      nf[s]=inf;
      while(!q.empty()){
          int x=q.front();
          q.pop();iq[x]=0;
          for(int i=head[x];i;i=nxt[i])
            if(w[i]&&d[to[i]]>d[x]+c[i]){
                d[to[i]]=d[x]+c[i];
                la[to[i]]=i;
                nf[to[i]]=min(nf[x],w[i]);
                if(!iq[to[i]]){
                  q.push(to[i]);
                  iq[to[i]]=1;
                }
            }
      }
      int x=la[t],be=Ans;
      if(d[t]==inf)return;
      while(x){
          w[x]-=nf[t];
          w[ano[x]]+=nf[t];
          Ans+=nf[t]*c[x];
          x=la[fm[x]];
      }
    }
}
int main(){
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
      char s[110];
      scanf("%s",s);
      for(j=1;j<=m;j++)beg[(i-1)*m+j]=s[j-1]-'0';
    }
    for(i=1;i<=n;i++){
      char s[110];
      scanf("%s",s);
      for(j=1;j<=m;j++)end[(i-1)*m+j]=s[j-1]-'0';
    }
    for(i=1;i<=n;i++){
      char s[110];
      scanf("%s",s);
      for(j=1;j<=m;j++)v[(i-1)*m+j]=s[j-1]-'0';
    }
    int N=n*m;
    s=3*N+20,t=s+1;
    for(i=1;i<=N;i++)le[i]=i,now[i]=i+N,ri[i]=i+2*N;
    for(i=1;i<=N;i++){
      int x=i/m+1,y=i%m;
      if(y==0)x--,y=m;
      if(beg[i]==0&&end[i]==1){
          add(le[i],now[i],1,v[i]/2);
          add(now[i],ri[i],1,(v[i]+1)/2);
          sum1++;
      }else if(beg[i]==1&&end[i]==0){
          add(le[i],now[i],1,(v[i]+1)/2);
          add(now[i],ri[i],1,v[i]/2);
          sum2++;
      }else {
          add(le[i],now[i],1,v[i]/2);
          add(now[i],ri[i],1,v[i]/2);
      }
      if(beg[i]==0)add(s,now[i],0,1);
      if(end[i]==0)add(now[i],t,0,1);
      goadd(i);
    }
    if(sum1!=sum2){
      puts("-1");
      return 0;
    }
    work();
    printf("%d\n",Ans/2);
    return 0;
}
posted @ 2019-02-09 14:17  水题收割者  阅读(218)  评论(0编辑  收藏  举报