平面图求最小割;
其实看bzoj1001一开始着实把我怔住了
AC的人暴多,可自己完全没思路
后来看了某大牛的ppt,才会做
一个月前做这题的吧,今天来简单回忆一下;
首先是欧拉公式
如果一个连通的平面图有n个点,m条边和f个面,那么f=m-n+2
我们把原图的每个面看成新图的一个点,对于原图中的每条边
如果边只属于一个面,那么给对应点连一个自环;
如果边两侧各有一个面,那么给对应点之间连一条无向边
这样,新图与原图的边一一对应;
可以发现,新图的一条路径对应原图的一个割
于是我们原图起点终点连一条边,增加一个附加面(也可以理解为把外面言直线st分为两个面);
按上述方法建新图,于是最小割问题转化为对新图求最短路;
最短路可以用堆优化dij;
这题我的dij+heap写的有进步
1 const inf=2147483647; 2 type link=^node; 3 node=record 4 po,len:longint; 5 next:link; 6 end; 7 point=record 8 num,loc:longint; 9 end; 10 11 var w:array[0..2020010] of link; 12 heap:array[0..2020010] of point; 13 where,d:array[0..2020010] of longint; 14 xie,hen,shu:array[0..1010,0..1010] of longint; 15 t,s,i,j,n,m,x,y:longint; 16 p:link; 17 18 procedure swap(var a,b:point); 19 var c:point; 20 begin 21 c:=a; 22 a:=b; 23 b:=c; 24 end; 25 26 procedure add(x,y,z:longint); 27 var p:link; 28 begin 29 new(p); 30 p^.po:=y; 31 p^.len:=z; 32 p^.next:=w[x]; 33 w[x]:=p; 34 end; 35 36 procedure up(i:longint); 37 var j,x,y:longint; 38 begin 39 j:=i shr 1; 40 while j>0 do 41 begin 42 if heap[i].num<heap[j].num then 43 begin 44 x:=heap[i].loc; 45 y:=heap[j].loc; 46 where[x]:=j; 47 where[y]:=i; 48 swap(heap[i],heap[j]); 49 i:=j; 50 j:=i shr 1; 51 end 52 else break; 53 end; 54 end; 55 56 procedure sift(i:longint); 57 var j,x,y:longint; 58 begin 59 j:=i shl 1; 60 while j<=s do 61 begin 62 if (j+1<=s) and (heap[j].num>heap[j+1].num) then inc(j); 63 if heap[i].num>heap[j].num then 64 begin 65 x:=heap[i].loc; 66 y:=heap[j].loc; 67 where[x]:=j; 68 where[y]:=i; 69 swap(heap[i],heap[j]); 70 i:=j; 71 j:=i shl 1; 72 end 73 else break; 74 end; 75 end; 76 77 procedure build; //复杂的建图,这种东西一定要谨慎,错误才会少; 78 var i:longint; 79 begin 80 for i:=1 to m-1 do 81 begin 82 add(1,i+1,hen[1,i]); 83 add(i+1,1,hen[1,i]); 84 end; 85 for i:=1 to n-1 do 86 begin 87 x:=(m-1)*(2*i-1)+1; 88 add(1,x,shu[i,m]); 89 add(x,1,shu[i,m]); 90 end; 91 92 for i:=1 to m-1 do 93 begin 94 x:=t-m+i; 95 add(t,x,hen[n,i]); 96 add(x,t,hen[n,i]); 97 end; 98 for i:=1 to n-1 do 99 begin 100 x:=(m-1)*(2*i-1)+2; 101 add(t,x,shu[i,1]); 102 add(x,t,shu[i,1]); 103 end; 104 105 for i:=2 to n-1 do 106 for j:=1 to m-1 do 107 begin 108 x:=(2*i-3)*(m-1)+j+1; 109 y:=x+m-1; 110 add(x,y,hen[i,j]); 111 add(y,x,hen[i,j]); 112 end; 113 114 for i:=1 to n-1 do 115 for j:=2 to m-1 do 116 begin 117 x:=(2*i-2)*(m-1)+j; 118 y:=x+m; 119 add(x,y,shu[i,j]); 120 add(y,x,shu[i,j]); 121 end; 122 123 for i:=1 to n-1 do 124 for j:=1 to m-1 do 125 begin 126 x:=(2*i-2)*(m-1)+j+1; 127 y:=x+m-1; 128 add(x,y,xie[i,j]); 129 add(y,x,xie[i,j]); 130 end; 131 end; 132 133 procedure dij; //最短路 134 var p:link; 135 mid,k,y:longint; 136 begin 137 p:=w[1]; 138 for i:=2 to t do 139 d[i]:=inf; 140 d[1]:=0; 141 while p<>nil do 142 begin 143 x:=p^.po; 144 d[x]:=min(d[x],p^.len); 145 p:=p^.next; 146 end; 147 s:=0; 148 for i:=2 to t do 149 begin 150 inc(s); 151 heap[s].num:=d[i]; 152 heap[s].loc:=i; //表示堆的这个位置是哪个点 153 where[i]:=s; //where表示这个点在堆的哪个位置 154 up(s); 155 end; 156 157 for k:=1 to t do 158 begin 159 mid:=heap[1].num; 160 if s=0 then break; 161 if mid=inf then break; 162 x:=heap[1].loc; 163 y:=heap[s].loc; 164 where[y]:=1; 165 166 swap(heap[1],heap[s]); //退堆 167 dec(s); 168 169 sift(1); 170 p:=w[x]; 171 while p<>nil do 172 begin 173 y:=p^.po; 174 if d[y]>p^.len+mid then //更新,入堆 175 begin 176 d[y]:=p^.len+mid; 177 heap[where[y]].num:=d[y]; 178 up(where[y]); 179 end; 180 p:=p^.next; 181 end; 182 end; 183 end; 184 185 begin 186 readln(n,m); 187 for i:=1 to n do 188 begin 189 for j:=1 to m-1 do 190 read(hen[i,j]); 191 end; 192 for i:=1 to n-1 do 193 begin 194 for j:=1 to m do 195 read(shu[i,j]); 196 end; 197 for i:=1 to n-1 do 198 begin 199 for j:=1 to m-1 do 200 read(xie[i,j]); 201 end; 202 203 if n=1 then //注意这种情况要特判 204 begin 205 t:=inf; 206 for i:=1 to m-1 do 207 t:=min(hen[1,i],t); 208 writeln(t); 209 halt; 210 end 211 else if m=1 then 212 begin 213 t:=inf; 214 for i:=1 to n-1 do 215 t:=min(t,shu[i,1]); 216 writeln(t); 217 halt; 218 end; 219 t:=(n-1)*(m-1)*2+2; //计算新图总点数 220 build; 221 dij; 222 writeln(d[t]); 223 end.