bzoj2668

来源:互联网 发布:端口聚合是什么意思 编辑:程序博客网 时间:2024/05/19 17:49

Description

有一个nm列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第i行第j列的格子只能参与mi,j次交换。

Input

第一行包含两个整数nm(1<=n, m<=20)。以下n行为初始状态,每行为一个包含m个字符的01串,其中0表示黑色棋子,1表示白色棋子。以下n行为目标状态,格式同初始状态。以下n行每行为一个包含m个0~9数字的字符串,表示每个格子参与交换的次数上限。
 

Output

输出仅一行,为最小交换总次数。如果无解,输出-1。

Sample Input

3 3
110
000
001
000
110
100
222
222
222

Sample Output

4



网络流

明显格子等价于可以互相穿过,棋子是一样的

原本就在位置上的棋子我们没必要移


program bzoj2668;const    zl:array [1..8,1..2] of longint=((1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1));vartot,u,v,x,y,count,ans,n,m,i,j,k:longint;    lim:array [0..21,0..21] of longint;    a,b:array [0..21,0..21] of char;    last,dis,root:array [0..801] of longint;    dl,point,next,cost,flow:array [0..100001] of longint;    ch:char;function anti (now:longint):longint;inline;begin    if now and 1 = 1 then exit(now+1)                            else exit(now-1);end;procedure connect (u,v,f,c:longint);inline;begin    inc(tot);    point[tot]:=v;    flow[tot]:=f;    cost[tot]:=c;    next[tot]:=root[u];    root[u]:=tot;end;procedure mcmf;begin    repeat        fillchar(dis,sizeof(dis),63);        tot:=0;         dl[0]:=0;        dis[0]:=0;        i:=0;        while i<=tot do            begin                k:=root[dl[i]];                while k<>0 do                    begin                        if (flow[k]>0)and(dis[point[k]]>dis[dl[i]]+cost[k]) then                            begin                                last[point[k]]:=k;                                dis[point[k]]:=dis[dl[i]]+cost[k];                                inc(tot);                                dl[tot]:=point[k];                            end;                        k:=next[k];                    end;                inc(i);            end;        if dis[801]>1000000 then break;         dec(count);        ans:=ans+dis[801];        i:=801;        while i<>0 do            begin                dec(flow[last[i]]);                inc(flow[anti(last[i])]);                i:=point[anti(last[i])];            end;    until false;end;begin    readln(n,m);    count:=0;    for i:=1 to n do        begin            for j:=1 to m do                begin                    read(a[i,j]);                    if a[i,j]='1' then inc(count);                end;            readln;        end;    k:=0;    for i:=1 to n do        begin            for j:=1 to m do                begin                    read(b[i,j]);                    if b[i,j]='1' then inc(k);                end;            readln;        end;    if count<>k then        begin            writeln(-1);            exit;        end;    for i:=1 to n do        begin            for j:=1 to m do                begin                    read(ch);                    lim[i,j]:=ord(ch)-48;                end;            readln;        end;    for i:=1 to n do        for j:=1 to m do            if (a[i,j]='1')and(b[i,j]='1') then                begin                    dec(count);                    k:=i*m-m+j;                    connect(k*2-1,k*2,lim[i,j] div 2,0);                    connect(k*2,k*2-1,0,0);                end                                                    else            if (a[i,j]='1')or(b[i,j]='1') then                begin                    k:=i*m-m+j;                    if lim[i,j]=0 then                        begin                            writeln(-1);                            exit;                        end;                    connect(k*2-1,k*2,(lim[i,j]-1) div 2 + 1,0);                    connect(k*2,k*2-1,0,0);                    if a[i,j]='1' then                        begin                            connect(0,k*2-1,1,0);                            connect(k*2-1,0,0,0);                        end;                    if b[i,j]='1' then                        begin                            connect(k*2,801,1,0);                            connect(801,k*2,0,0);                        end;                end                                                    else                begin                    k:=i*m-m+j;                    connect(k*2-1,k*2,lim[i,j] div 2,0);                    connect(k*2,k*2-1,0,0);                end;    for i:=1 to n do        for j:=1 to m do            for k:=1 to 8 do                begin                    x:=i+zl[k,1];                    y:=j+zl[k,2];                    if (x<1)or(x>n)or(y<1)or(y>m) then continue;                    u:=i*m-m+j;                    v:=x*m-m+y;                    connect(u*2,v*2-1,maxlongint div 10,1);                    connect(v*2-1,u*2,0,-1);                end;    mcmf;    if count<>0 then        begin            writeln(-1);            exit;        end;    writeln(ans);end.