对于这种题很容易看出是费用流吧……
但这道题不容易建模;
首先是怎么表示目标状态和其实状态,看起来有黑有白很复杂
但实际上,不难发现,白色格子没什么用,起决定作用的是黑格子
也就是我们可以把问题简化:我们怎么把开始的黑格子移到目标位置
但这个移动不是一般的移动;
在一条路径中,不难发现,起始两点是只要交换一次,其他路径上个点都是要交换2次
由于题目给出的限制是点的交换次数限制c,所以不难想到要拆点
但是平常的拆两点好像无法表示这个特征,
于是我们就拆成3个点……
p1--->p0--->p2
p1表示交换进来,p2表示交换出去;
所以不难得出:
对于每个点,如果它是原图中的黑点,连边<p1,p0,c/2,0>,<p0,p2,(c+1)/2,0>,<s,p0,1,0>;
如果它是新图中的黑点,连边<p1,p0,(c+1)/2>,<p0,p2,c/2,0>,<p0,t,1,0>;
注意存在有的点在新图原图都是黑点的情况(在这里WA了一次)
如果它在两个图中都是白点,那么连边<p1,p0,c/2,0>,<p0,p2,c/2,0>
最后对于原图中任意可达两点,连边<pi2,pj1,inf,1>
注意这道题可以交换对角线,还要判断是否可行,细节挺多
1 const dx:array[1..8] of integer=(-1,1,0,0,1,-1,-1,1); 2 dy:array[1..8] of integer=(0,0,1,-1,1,-1,1,-1); 3 inf=10000007; 4 type node=record 5 next,point,cost,flow:longint; 6 end; 7 8 var edge:array[0..1000010] of node; 9 p,pre,cur,d:array[0..2010] of longint; 10 v:array[0..2010] of boolean; 11 a,b,c:array[0..30,0..30] of integer; 12 q:array[0..1001000] of longint; 13 ch,t,n,m,i,j,k,x,y,po,tot,sum,ans,len:longint; 14 s:string; 15 16 procedure add(x,y,f,w:longint); 17 begin 18 inc(len); 19 edge[len].point:=y; 20 edge[len].flow:=f; 21 edge[len].cost:=w; 22 edge[len].next:=p[x]; 23 p[x]:=len; 24 end; 25 26 function spfa:boolean; 27 var i,x,y,f,r:longint; 28 begin 29 fillchar(v,sizeof(v),false); 30 v[0]:=true; 31 for i:=1 to t do 32 d[i]:=inf; 33 d[0]:=0; 34 f:=1; 35 r:=1; 36 q[f]:=0; 37 while f<=r do 38 begin 39 x:=q[f]; 40 v[x]:=false; 41 i:=p[x]; 42 while i<>-1 do 43 begin 44 y:=edge[i].point; 45 if edge[i].flow>0 then 46 if d[y]>d[x]+edge[i].cost then 47 begin 48 d[y]:=d[x]+edge[i].cost; 49 pre[y]:=x; 50 cur[y]:=i; 51 if not v[y] then 52 begin 53 inc(r); 54 q[r]:=y; 55 v[y]:=true; 56 end; 57 end; 58 i:=edge[i].next; 59 end; 60 inc(f); 61 end; 62 if d[t]=inf then exit(false) else exit(true); 63 end; 64 65 procedure mincost; 66 var i,j,neck:longint; 67 begin 68 while spfa do 69 begin 70 i:=t; 71 neck:=inf; 72 while i<>0 do 73 begin 74 j:=cur[i]; 75 if neck>edge[j].flow then neck:=edge[j].flow; 76 i:=pre[i]; 77 end; 78 i:=t; 79 while i<>0 do 80 begin 81 j:=cur[i]; 82 dec(edge[j].flow,neck); 83 inc(edge[j xor 1].flow,neck); 84 i:=pre[i]; 85 end; 86 ans:=ans+d[t]*neck; 87 dec(ch,neck); 88 if ch=0 then break; 89 end; 90 end; 91 92 begin 93 readln(n,m); 94 len:=-1; 95 fillchar(p,sizeof(p),255); 96 t:=3*n*m+1; 97 for i:=1 to n do 98 begin 99 readln(s); 100 for j:=1 to m do 101 begin 102 a[i,j]:=ord(s[j])-48; 103 tot:=tot+a[i,j]; 104 end; 105 end; 106 for i:=1 to n do 107 begin 108 readln(s); 109 for j:=1 to m do 110 begin 111 b[i,j]:=ord(s[j])-48; 112 sum:=sum+b[i,j]; 113 end; 114 end; 115 for i:=1 to n do 116 begin 117 readln(s); 118 for j:=1 to m do 119 c[i,j]:=ord(s[j])-48; 120 end; 121 if sum<>tot then 122 begin 123 writeln(-1); 124 halt; 125 end 126 else ch:=sum; 127 sum:=n*m; 128 for i:=1 to n do 129 begin 130 for j:=1 to m do 131 begin 132 x:=(i-1)*m+j; 133 if a[i,j]=1 then 134 begin 135 add(x+sum,x,c[i,j] shr 1,0); 136 add(x,x+sum,0,0); 137 add(x,x+2*sum,(c[i,j]+1) shr 1,0); 138 add(x+2*sum,x,0,0); 139 add(0,x,1,0); 140 add(x,0,0,0); 141 if b[i,j]=1 then //细节 142 begin 143 add(x,t,1,0); 144 add(t,x,0,0); 145 end; 146 end 147 else if b[i,j]=1 then 148 begin 149 add(x+sum,x,(c[i,j]+1) shr 1,0); 150 add(x,x+sum,0,0); 151 add(x,x+2*sum,c[i,j] shr 1,0); 152 add(x+2*sum,x,0,0); 153 add(x,t,1,0); 154 add(t,x,0,0); 155 end 156 else if (a[i,j]+b[i,j]=0) then 157 begin 158 add(x+sum,x,c[i,j] shr 1,0); 159 add(x,x+sum,0,0); 160 add(x,x+2*sum,c[i,j] shr 1,0); 161 add(x+2*sum,x,0,0); 162 end; 163 end; 164 end; 165 166 for i:=1 to n do 167 for j:=1 to m do 168 begin 169 po:=(i-1)*m+j; 170 for k:=1 to 8 do 171 begin 172 x:=i+dx[k]; 173 y:=j+dy[k]; 174 if (x<=n) and (y<=m) and (x>0) and (y>0) then 175 begin 176 tot:=(x-1)*m+y; 177 add(po+2*sum,tot+sum,inf,1); 178 add(tot+sum,po+2*sum,0,-1); 179 end; 180 end; 181 end; 182 mincost; 183 if ch<>0 then writeln(-1) else writeln(ans); 184 end.