平面图求最小割;

其实看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.
View Code

 

posted on 2014-04-09 22:54  acphile  阅读(330)  评论(0编辑  收藏  举报