题目链接
两个很显然的性质:
1.我们只会交换两个颜色不同的棋子。
2.如果路上有棋子,那么这条路肯定没有前面的棋子走优。
那么,就相当于黑棋经过一堆白棋走到一个白棋。
我们来考虑交换问题。
除了一条交换路径的头尾交换一次之外,每个点都要被交换两次。
怎么解决?
解法十分显然,拆三个点,a向b连边,b向c连边我们规定从起点从b出发,终点在b结束,那么消耗的流量就是所消耗的交换次数。
a,b,c连边的流量怎么设置呢?
很容易想到,两条边各取。
我们再来考虑头尾的交换。
那些一开始为黑,最后为白的点肯定要把这个点释放出去,那么我们先优先给出边bc流量加1。
那些一开始为白,最后为黑的点肯定要获得一个黑点,那么我们先优先给入边ac流量加1.
剩下的除以2均摊就可以了,因为一个黑点只会经过这里,不会停在这里,除以2带来的价值是最大的。
#include
#include
#include
#include
#include
using namespace std;
int n,m;
char st[25][25],ed[25][25],p[25][25];
struct edge{
int x,y,next,c,cos;
}s[50010];
int begin,end,len=1;
int fx[8]={-1,-1,-1,0,0,1,1,1};
int fy[8]={-1,0,1,-1,1,-1,0,1};
int ans=0;
int d[1210],last[1210],mmin[1210],first[1210];
bool tf[1210];
queue f;
void ins(int x,int y,int c,int cos){
len++;s[len]=(edge){x,y,first[x],c,cos};first[x]=len;
len++;s[len]=(edge){y,x,first[y],0,-cos};first[y]=len;
}
bool SPFA(int&flow,int&cost){
mmin[begin]=1e9;
memset(d,63,sizeof(d));d[begin]=0;
memset(tf,false,sizeof(tf));tf[begin]=true;
f.push(begin);
while(!f.empty()){
int x=f.front();f.pop();tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(d[y]>d[x]+s[i].cos && s[i].c>0){
d[y]=d[x]+s[i].cos;
last[y]=i;
mmin[y]=min(mmin[x],s[i].c);
if(!tf[y]){
tf[y]=true;
f.push(y);
}
}
}
}
if(d[end]==d[end+1]) return false;
flow+=mmin[end];
cost+=mmin[end]*d[end];
int now=end;
while(now!=begin){
s[last[now]].c-=mmin[end];s[last[now]^1].c+=mmin[end];
now=s[last[now]].x;
}
return true;
}
void MCMF(){
int flow=0,cost=0;
while(SPFA(flow,cost));
if(flow==ans) printf("%d\n",cost);
else printf("-1");
}
int main(){
scanf("%d %d",&n,&m);
int data,temp,t,x,y;
begin=0;end=(data=n*m)*3+1;
for(int i=1;i<=n;i++) scanf("%s",st[i]+1);
for(int i=1;i<=n;i++) scanf("%s",ed[i]+1);
for(int i=1;i<=n;i++) scanf("%s",p[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
temp=(i-1)*m+j,t=p[i][j]-'0';
if(st[i][j]==ed[i][j]) ins(temp,temp+data,t/2,0),ins(temp+data,temp+data+data,t/2,0);
else if(st[i][j]=='0'){
ins(begin,temp+data,1,0);
ins(temp,temp+data,t/2,0);ins(temp+data,temp+data+data,(t+1)/2,0);
}
else{
ins(temp+data,end,1,0);ans++;
ins(temp,temp+data,(t+1)/2,0);ins(temp+data,temp+data+data,t/2,0);
}
for(int k=0;k<8;k++){
x=i+fx[k],y=j+fy[k];
if(x>=1 && x<=n && y>=1 && y<=m);else continue;
t=(x-1)*m+y;
ins(temp+data+data,t,1e9,1);
}
}
MCMF();
}