因为有交换次数的限制,所以把每个点
x
x
x 拆成
3
3
3 个点:
i
n
(
x
)
,
o
u
t
(
x
)
,
m
i
d
(
x
)
in(x), out(x), mid(x)
in(x),out(x),mid(x)。
记
a
[
x
]
a[x]
a[x] 表示
⌊
\lfloor
⌊ 将相邻的白棋移到位置
x
x
x
⌋
\rfloor
⌋ 这一操作的次数。
b
[
x
]
b[x]
b[x] 表示
⌊
\lfloor
⌊ 将位置
x
x
x 的白棋移到相邻位置
⌋
\rfloor
⌋ 这一操作的次数。
c
[
x
]
c[x]
c[x] 表示
⌊
\lfloor
⌊ 将相邻的白棋移到位置
x
x
x
⌋
\rfloor
⌋ 和
⌊
\lfloor
⌊ 将位置
x
x
x的白棋移到相邻位置
⌋
\rfloor
⌋ 这两个操作的次数之和的上限,也就是输入的第
3
3
3 个矩阵。
如果初始和目标局面中,
x
x
x 均为白棋或均为空地,那么
a
[
x
]
=
b
[
x
]
a[x]=b[x]
a[x]=b[x],所以
a
[
x
]
,
b
[
x
]
a[x],b[x]
a[x],b[x] 的上限均为
⌊
c
[
x
]
2
⌋
\lfloor\frac{c[x]}{2}\rfloor
⌊2c[x]⌋。
如果
x
x
x 初始为白棋,目标为空地,那么
a
[
x
]
+
1
=
b
[
x
]
a[x]+1=b[x]
a[x]+1=b[x],那么
a
[
x
]
a[x]
a[x] 的上限是
⌊
c
[
x
]
2
⌋
\lfloor\frac{c[x]}{2}\rfloor
⌊2c[x]⌋,
b
[
x
]
b[x]
b[x] 的上限是
⌈
c
[
x
]
2
⌉
\lceil\frac{c[x]}{2}\rceil
⌈2c[x]⌉。
如果
x
x
x 初始为空地,目标为白棋,那么
b
[
x
]
+
1
=
a
[
x
]
b[x]+1=a[x]
b[x]+1=a[x],那么
a
[
x
]
a[x]
a[x] 的上限是
⌈
c
[
x
]
2
⌉
\lceil\frac{c[x]}{2}\rceil
⌈2c[x]⌉,
b
[
x
]
b[x]
b[x] 的上限是
⌊
c
[
x
]
2
⌋
\lfloor\frac{c[x]}{2}\rfloor
⌊2c[x]⌋。
然后连边
(
i
n
(
x
)
,
m
i
d
(
x
)
,
a
[
x
]
的
上
限
,
0
)
,
(
m
i
d
(
x
)
,
o
u
t
(
x
)
,
b
[
x
]
的
上
限
,
0
)
(in(x),mid(x),a[x]的上限,0),(mid(x),out(x),b[x]的上限,0)
(in(x),mid(x),a[x]的上限,0),(mid(x),out(x),b[x]的上限,0)。
考虑源点和汇点的连边。
首先我们在某些位置上放白棋:假设在位置
x
x
x 放了
1
1
1 个白棋,那么连边:
(
S
,
m
i
d
(
x
)
,
1
,
0
)
(S,mid(x),1,0)
(S,mid(x),1,0)。
同理,如果最后要在位置
x
x
x 拿走
1
1
1 个白棋,那么连边:
(
m
i
d
(
x
)
,
T
,
1
,
0
)
(mid(x),T,1,0)
(mid(x),T,1,0)。
最后对于任意相邻两点
x
,
y
x,y
x,y,连边
(
o
u
t
(
x
)
,
i
n
(
y
)
,
∞
,
0
)
(out(x),in(y),∞,0)
(out(x),in(y),∞,0),表示白棋的转移。
求最小费用最大流就是答案。
注意特判无解:初始和目标局面白棋个数不同,或者最大流小于白棋个数。
Code
#include<bits/stdc++.h>usingnamespace std;constint e =1e6+5, o =1e3+5, dx[]={1,0,-1,0,1,-1,-1,1};constint inf =0x3f3f3f3f, dy[]={0,1,0,-1,1,-1,1,-1};bool vis[e];int adj[e], nxt[e], pre[e], num =1, go[e], n, m, s, t, nm, a[e], frm[e], c[e], f[e], d[e];int ans, co[e], cs, ct, bs[o][o], bt[o][o], mxf;inlinevoidadd(int x,int y,int v,int w){
nxt[++num]= adj[x]; frm[num]= x; adj[x]= num; go[num]= y; c[num]= v; co[num]= w;
nxt[++num]= adj[y]; frm[num]= y; adj[y]= num; go[num]= x; co[num]=-w;}inlineboolbfs(){
queue<int>q;int i;for(i =1; i <= t; i++) d[i]= inf;
d[s]= pre[s]=0; a[s]= inf;
q.push(s);while(!q.empty()){int u = q.front();
q.pop();
vis[u]=0;for(i = adj[u]; i; i = nxt[i]){int v = go[i];if(c[i]> f[i]&& d[v]> d[u]+ co[i]){
d[v]= d[u]+ co[i];
pre[v]= i;
a[v]=min(a[u], c[i]- f[i]);if(!vis[v]) vis[v]=1, q.push(v);}}}if(d[t]== inf)return0;
ans += d[t]* a[t];
mxf += a[t];int u = t;while(u != s){
f[pre[u]]+= a[t];
f[pre[u]^1]-= a[t];
u = frm[pre[u]];}return1;}inlineintin(int x,int y){return(x -1)* m + y;}inlineintmid(int x,int y){return(x -1)* m + y + nm;}inlineintout(int x,int y){return(x -1)* m + y +2* nm;}intmain(){scanf("%d%d",&n,&m); nm = n * m; s =3* nm +1; t = s +1;int i, j, x, k;for(i =1; i <= n; i++)for(j =1; j <= m; j++){char ch;
cin >> ch;
bs[i][j]= ch -'0';}for(i =1; i <= n; i++)for(j =1; j <= m; j++){char ch;
cin >> ch;
bt[i][j]= ch -'0';}for(i =1; i <= n; i++)for(j =1; j <= m; j++){char ch;
cin >> ch;
x = ch -'0';if(bs[i][j])add(s,mid(i, j),1,0), cs++;if(bt[i][j])add(mid(i, j), t,1,0), ct++;if(bs[i][j]== bt[i][j]){add(in(i, j),mid(i, j), x /2,0);add(mid(i, j),out(i, j), x /2,0);}elseif(bs[i][j]){add(in(i, j),mid(i, j), x /2,0);add(mid(i, j),out(i, j),(x +1)/2,0);}else{add(in(i, j),mid(i, j),(x +1)/2,0);add(mid(i, j),out(i, j), x /2,0);}for(k =0; k <8; k++){int x = dx[k]+ i, y = dy[k]+ j;if(x <1|| y <1|| x > n || y > m)continue;add(out(i, j),in(x, y), inf,1);}}if(cs != ct){puts("-1");return0;}while(bfs());if(mxf != ct)puts("-1");else cout << ans << endl;return0;}