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;
}