[CQOI2012] 交换棋子 (费用流)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<queue> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } queue<int> que; const int MAXN=100001; const int N=1001; struct node{ int u,v,cost,w,nex; }x[MAXN<<2]; int head[MAXN],S,T,cnt,dis[MAXN],vis[MAXN],cost,INF=INT_MAX; void add(int u,int v,int cost,int w){ // printf("u:%d v:%d cost:%d w:%d\n",u,v,cost,w); x[cnt].u=u,x[cnt].v=v,x[cnt].cost=cost,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;swap(u,v),w=0,cost=-cost; x[cnt].u=u,x[cnt].v=v,x[cnt].cost=cost,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++; } bool spfa(){ memset(dis,127/3,sizeof(dis)),memset(vis,0,sizeof(vis)); int inf=dis[0];dis[S]=0,vis[S]=1,que.push(S); while(!que.empty()){ int xx=que.front();que.pop(); for(int i=head[xx];i!=-1;i=x[i].nex){ if(x[i].w&&dis[x[i].v]>dis[xx]+x[i].cost){ dis[x[i].v]=dis[xx]+x[i].cost; if(!vis[x[i].v]) vis[x[i].v]=1,que.push(x[i].v); } }vis[xx]=0; }return dis[T]!=inf; } int dfs(int u,int flow){ // printf("u:%d flow:%d\n",u,flow); if(u==T) return flow; int used=0;vis[u]=1; for(int i=head[u];i!=-1;i=x[i].nex){ if(x[i].w&&dis[x[i].v]==dis[u]+x[i].cost&&!vis[x[i].v]){ int slow=dfs(x[i].v,min(flow-used,x[i].w));used+=slow; x[i].w-=slow,x[i^1].w+=slow; cost+=slow*x[i].cost; if(used==flow) break; } }if(!used) dis[u]=-1; vis[u]=0; return used; } int dinic(){ int ans=0;cost=0; while(spfa()){memset(vis,0,sizeof(vis)),ans+=dfs(S,INF);} return ans; } char A[N][N],B[N][N],lim[N][N]; int n,m,sum; int dx[8]={1,1,1,-1,-1,-1,0,0}; int dy[8]={1,0,-1,1,0,-1,1,-1}; int Q(int x,int y){return (x-1)*m+y;} int main(){ // freopen("8.in","r",stdin); memset(head,-1,sizeof(head)); n=read(),m=read();S=0,T=n*m*3+1; for(int i=1;i<=n;i++) scanf("%s",A[i]+1); for(int i=1;i<=n;i++) scanf("%s",B[i]+1); for(int i=1;i<=n;i++) scanf("%s",lim[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(A[i][j]==B[i][j]&&A[i][j]==1) continue; A[i][j]-='0',B[i][j]-='0',lim[i][j]-='0'; if(A[i][j]==B[i][j]){ add(Q(i,j),Q(i,j)+n*m,0,lim[i][j]/2); add(Q(i,j)+2*n*m,Q(i,j),0,lim[i][j]); continue; } if(A[i][j]==1){ sum++; add(S,Q(i,j),0,1); add(Q(i,j),Q(i,j)+n*m,0,(lim[i][j]+1)/2); add(Q(i,j)+2*n*m,Q(i,j),0,(lim[i][j]-1)/2); continue; } if(B[i][j]==1){ add(Q(i,j),Q(i,j)+n*m,0,(lim[i][j]-1)/2); add(Q(i,j)+2*n*m,Q(i,j),0,(lim[i][j]+1)/2); add(Q(i,j),T,0,1); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ for(int k=0;k<8;k++){ int bx=i+dx[k],by=j+dy[k]; if(bx>=1&&bx<=n&&by>=1&&by<=m){ add(Q(i,j)+n*m,Q(bx,by)+2*n*m,1,INF); } } } } int Ans=dinic(); if(Ans!=sum){printf("-1");return 0;} printf("%d\n",cost); }/* 1 2 1 0 0 1 1 1 */