题目链接:https://www.luogu.org/problem/P3159;
思路:这个题最难的地方在于建图;
图是有黑点和白点构成,我们只考虑黑点的移动就行。
对于一个黑点,如果他向相邻的点移动,就相当于两个点的交换次数都减一;
对于一个当前点,可能有其他的点交换到当前点,也可能是当前点交换到其他的点,所以,我们可以把一个点拆成三个点(a,b,c);
如果有其他点交换到当前点,假设是 X 交换到 Y,就相当于 X.b --> X.c --> Y.a --> Y.b;
好了,现在开始讲如何建图:
对于一个点(now),如果原图是黑点终图是白点,就相当于流出的值>流入的值,
就可以连边 now.a --> now.b,费用为0,流量为(交换次数+1)/2;now.b --> now.c,费用为0,流量为 (交换次数/2);
如果原图是白点终图是黑点,就相当于 流入>流出,
连边 now.a --> now.b,费用为0,流量为(交换次数/2);now.b --> now.c,费用为0,流量为 (交换次数+1) / 2;
然后将源点S与原图黑点的a连边,流量为1,费用为0,终图黑点c与汇点T连边,流量为1,费用为0;
相邻的点连边,X.c --> Y.a,流量为information,费用为1;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=2000;
struct node
{
int v,ne,w,cost,cap;
} q[N*N*2];
int f[N],pre[N],dis[N],vis[N];
int dist[8][2]={0,1,1,0,0,-1,-1,0,1,1,1,-1,-1,1,-1,-1};
int e,n,m,s,t,sum,hsy;
void add_op(int a,int b,int c,int d)
{
q[e].v=b;
q[e].w=c;
q[e].ne=f[a];
q[e].cost=d;
f[a]=e++;
}
void add(int a,int b,int c,int d)
{
add_op(a,b,c,d);
add_op(b,a,0,-d);
}
bool spaf()
{
queue<int>que;
for(int i=0; i<=t; i++)
{
vis[i]=0;
pre[i]=-1;
dis[i]=inf;
}
vis[s]=1;
dis[s]=0;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=0;
for(int i=f[u]; i!=-1; i=q[i].ne)
{
int v=q[i].v,w=q[i].w,c=q[i].cost;
if(dis[v]>dis[u]+c&&w)
{
dis[v]=dis[u]+c;
pre[v]=i;
if(vis[v]==0)
{
vis[v]=1;
que.push(v);
}
}
}
}
return pre[t]!=-1;
}
void MCMF()
{
int flow=0,cost=0;
while(spaf())
{
int mini=inf;
for(int i=pre[t]; i!=-1; i=pre[q[i^1].v])
mini=min(mini,q[i].w);
for(int i=pre[t]; i!=-1; i=pre[q[i^1].v])
{
q[i].w-=mini;
q[i^1].w+=mini;
cost+=q[i].cost*mini;
}
flow+=mini;
}
if(flow!=sum||flow!=hsy) printf("-1\n");
else printf("%d\n",cost);
}
void change(char x[][25],int y[][25])
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
y[i][j]=x[i][j]-'0';
}
char MP[25][25];
int mark[25][25],num[25][25],st[25][25],en[25][25];
bool judge(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m) return true;
return false;
}
int cal(int x,int y)
{
return (x-1)*m+y;
}
int main()
{
memset(f,-1,sizeof(f));
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",MP[i]+1);
change(MP,st);
for(int i=1;i<=n;i++) scanf("%s",MP[i]+1);
change(MP,en);
for(int i=1;i<=n;i++) scanf("%s",MP[i]+1);
change(MP,num);
s=0;t=n*m*3+1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int tmp=cal(i,j);
if(st[i][j]==1&&en[i][j]==0)
{
add(tmp,n*m+tmp,num[i][j]/2,0);
add(n*m+tmp,n*m*2+tmp,(1+num[i][j])/2,0);
}
if(st[i][j]==0&&en[i][j]==1)
{
add(tmp,n*m+tmp,(num[i][j]+1)/2,0);
add(tmp+n*m,n*m*2+tmp,num[i][j]/2,0);
}
if(st[i][j]==en[i][j])
{
add(tmp,n*m+tmp,num[i][j]/2,0);
add(tmp+n*m,n*m*2+tmp,num[i][j]/2,0);
}
if(st[i][j]==1) add(s,tmp+n*m,1,0),sum++;
if(en[i][j]==1) add(tmp+n*m,t,1,0),hsy++;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k<8;k++)
{
if(judge(i+dist[k][0],j+dist[k][1]))
add(n*m*2+cal(i,j),cal(i+dist[k][0],j+dist[k][1]),inf,1);
}
}
}
if(hsy!=sum)
{
printf("-1\n");
return 0;
}
MCMF();
return 0;
}