http://www.lydsy.com/JudgeOnline/problem.php?id=2668
網絡流。
注意拆點的技巧
開始拆點的時候沒有注意點的出入關係,產生了“傳遞性”,導致混亂
理清楚關係:
限制的是交換次數
交換次數=sum{交換邊流量}
所以所有的交換邊連向一個點來限制次數
媽呀還是不對
點流量限制不用再拆點,只需要分類討論一下就可以了。。。。。。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)
#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u) for(int i=head[u];~i;i=e[i].next)
#define LL long long
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
////////////////////////////////////////////////
const int inf=0x3f3f3f3f;
const int N=1000;
const int M=10000;
int n,m,cnt1;
char beg[25][25],end[25][25],lim[25][25];
int A[25][25],B[25][25],tot;
int dx[]={1,-1,0,0,1,1,-1,-1};
int dy[]={0,0,1,-1,-1,1,-1,1};
int S,T;
struct edge{int v,f,c,next;}e[M];
int head[N],k;
int d[N],q[N*100],vis[N],clk;
////////////////////////////////////////////////
void adde(int u,int v,int f,int c){e[k]=(edge){v,f,c,head[u]};head[u]=k++;}
void ins(int u,int v,int f1,int f2,int c){adde(u,v,f1,c);adde(v,u,f2,-c);}
bool judge()
{
int cnt=0;
rep(i,1,n) rep(j,1,m) cnt+=beg[i][j]=='1';
cnt1=cnt;
rep(i,1,n) rep(j,1,m) cnt-=end[i][j]=='1';
return cnt==0;
}
bool spfa()
{
static bool inq[N]; MS(d,inf); d[q[0]=S]=0;
for(int u,v,l=0,r=1;l<r;)
{
u=q[l++]; inq[u]=0;
INE(i,u) if(e[i].f)
if(d[v=e[i].v]>d[u]+e[i].c)
{
d[v=e[i].v]=d[u]+e[i].c;
if(!inq[v]) inq[q[r++]=v]=1;
}
}
return d[T]<inf;
}
int dfs(int u,int a)
{
vis[u]=clk;
if(u==T) return a;
INE(i,u) if(e[i].f && vis[e[i].v]!=clk && d[e[i].v]==d[u]+e[i].c)
if(int t=dfs(e[i].v,min(a,e[i].f)))
return e[i].f-=t,e[i^1].f+=t,t;
return 0;
}
pair<int,int> zkw()
{
int f=0,c=0;
while(spfa()) do
{
int t=dfs(S,inf);
f+=t; c+=t*d[T];
}while(vis[T]==clk++);
return make_pair(f,c);
}
////////////////////////////////////////////////
void input()
{
MS(head,-1);
n=read(); m=read();
rep(i,1,n) scanf("%s",beg[i]+1);
rep(i,1,n) scanf("%s",end[i]+1);
rep(i,1,n) scanf("%s",lim[i]+1);
}
void solve()
{
if(!judge())
{
puts("-1");
return;
}
rep(i,1,n) rep(j,1,m) A[i][j]=++tot;
rep(i,1,n) rep(j,1,m) B[i][j]=++tot;
S=0; T=++tot;
rep(i,1,n) rep(j,1,m)
{
int flag=0;
if(beg[i][j]=='1') ins(S,A[i][j],1,0,0),flag++;
if(end[i][j]=='1') ins(B[i][j],T,1,0,0),flag++;
ins(A[i][j],B[i][j],flag+lim[i][j]-'0'>>1,0,1);
rep(k,0,7)
{
int nx=i+dx[k],ny=j+dy[k];
if(nx<1 || nx>n || ny<1 || ny>m) continue;
ins(B[i][j],A[nx][ny],inf,0,0);
}
}
pair<int,int> ret=zkw();
if(ret.first!=cnt1)
{
puts("-1");
return;
}
printf("%d\n",ret.second-cnt1);
}
////////////////////////////////////////////////
int main()
{
freopen("C.in","r",stdin); freopen("C.out","w",stdout);
input(),solve();
return 0;
}