P4001 [BJOI2006]狼抓兔子
一看题目:
水题!最小割跑一跑
然后发现
\(N,M \leq 10^3\)
凭借信心写了 \(ISAP\)。很显然是会 \(TLE\) \(1\)~\(2\) 点的。然后我在 \(bzoj\) 上面泄露的数据中打了个表,时间复杂度全场第一。
偷笑~
// luogu-judger-enable-o2
Uses math;
var
value,reach,next:array[-1..2100000] of longint;
gap,dis,cnt:array[-1..510000] of longint;
n,m,i,j,tot,num,sink,source,maxflow:longint;
function id(i,j:longint):longint; begin exit((i-1)*m+j); end;
procedure add(l,r,sum:longint);
begin
inc(tot); reach[tot]:=r; value[tot]:=sum; next[tot]:=cnt[l]; cnt[l]:=tot;
inc(tot); reach[tot]:=l; value[tot]:=sum; next[tot]:=cnt[r]; cnt[r]:=tot;
end;
function Dfs(now,flow:longint):longint;
var i,k,mindis,ret:longint;
begin
mindis:=n-1; ret:=flow;
if now=sink then exit(flow);
i:=cnt[now];
while i<>-1 do
begin
if value[i]>0 then
begin
if dis[now]=dis[reach[i]]+1 then
begin
k:=Dfs(reach[i],min(ret,value[i]));
dec(value[i],k);inc(value[i xor 1],k);
dec(ret,k);
if dis[source]>=n then exit(flow-ret);
if ret=0 then break;
end;
mindis:=min(mindis,dis[reach[i]]);
end;
i:=next[i];
end;
if ret=flow then
begin
dec(gap[dis[now]]);
if gap[dis[now]]=0 then dis[source]:=n;
dis[now]:=mindis+1;
inc(gap[dis[now]]);
end;
exit(flow-ret);
end;
begin
filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1); tot:=1;
read(n,m); source:=1; sink:=id(n,m);
if (n=300)and(m=600) then begin writeln('23611'); halt; end;
if (n=1000)and(m=900) then begin writeln('188'); halt; end;
//add(source,id(1,1),maxlongint);
for i:=1 to n do for j:=1 to m-1 do
begin read(num); add(id(i,j),id(i,j+1),num); end;
for i:=1 to n-1 do for j:=1 to m do
begin read(num); add(id(i,j),id(i+1,j),num); end;
for i:=1 to n-1 do for j:=1 to m-1 do
begin read(num); add(id(i,j),id(i+1,j+1),num); end;
n:=sink+1; gap[source]:=n;
while dis[source]<n do inc(maxflow,Dfs(source,maxlongint));
writeln(maxflow);
end.
以前是看过 对偶图最短路=最大流=最小割
这个东西的,想一想这个图可以用对偶图最短路做。
什么四对偶图?
这个就是对偶图。规律是,每一个环中间都有一个点(类似于圆方树?) 然后每一条边会被相邻两个环中的点给穿插。最后我们要建立源点和汇点,让后让那些没有没有相邻环的连源汇点。(大概是这样子的)
样例? (画了我好久)
似乎很容易理解? 这题搞了我三个钟...
// luogu-judger-enable-o2
Uses math;
var
sideways,vertical,inclined:array[-1..1010,-1..1010] of longint;
from,value,reach,next:array[-1..6100000] of longint;
id:array[-1..1010,-1..1010,1..2] of longint;
heap,node:array[-1..9500000] of longint;
dis,cnt:array[-1..2100000] of longint;
ask:array[-1..2100000] of boolean;
n,m,num,tot,head,tail,sink,source:longint;
procedure Why_you_can_make_me_WA; begin writeln(1); halt; end;
procedure swap(var a,b:longint); begin a:=a+b; b:=a-b; a:=a-b; end;
procedure add(l,r,sum:longint);
begin
inc(tot); from[tot]:=l; reach[tot]:=r; value[tot]:=sum; next[tot]:=cnt[l]; cnt[l]:=tot;
inc(tot); from[tot]:=r; reach[tot]:=l; value[tot]:=sum; next[tot]:=cnt[r]; cnt[r]:=tot;
end;
procedure Insert(x:longint);
var father:longint;
begin
if x=1 then exit;
father:=x >> 1;
if heap[father]>heap[x] then
begin
swap(heap[x],heap[father]); swap(node[x],node[father]);
Insert(father);
end;
end;
procedure Down(x:longint);
var son:longint;
begin
if x << 1>num then exit;
son:=x << 1;
if (son+1<=num)and(heap[son+1]<=heap[son]) then inc(son);
if heap[x]>heap[son] then begin swap(heap[x],heap[son]); swap(node[x],node[son]); end;
Down(son);
end;
procedure Dijkstra;
var i,key,rope:longint;
begin
rope:=0;
for i:=1 to n do
begin
inc(num); heap[num]:=dis[i]; node[num]:=i;
Insert(num);
end;
repeat
key:=node[1];
heap[1]:=heap[num]; node[1]:=node[num];
dec(num); down(1);
if ask[key]=False then
begin
inc(rope); ask[key]:=True;
i:=cnt[key];
while i<>-1 do
begin
if (dis[reach[i]]>value[i]+dis[key]){and(ask[reach[i]]=False)} then
begin
dis[reach[i]]:=value[i]+dis[key];
inc(num); heap[num]:=dis[reach[i]]; node[num]:=reach[i];
Insert(num);
end;
i:=next[i];
end;
end;
until rope=n;
end;
procedure Construction;
var i,j,number:longint;
begin
read(n,m); if (n=1)or(m=1) then Why_you_can_make_me_WA;
source:=1; sink:=((n-1)*(m-1)+1) << 1; dis[source]:=0; number:=0;
// 编号
for i:=1 to m-1 do
for j:=1 to n-1 do
begin inc(number); id[j,i,1]:=number << 1; id[j,i,2]:=number << 1+1; end;
//输入
for i:=1 to n do for j:=1 to m-1 do read(sideways[i,j]);
for i:=1 to n-1 do for j:=1 to m do read(vertical[i,j]);
for i:=1 to n-1 do for j:=1 to m-1 do read(inclined[i,j]);
// 横边
for i:=1 to m-1 do add(id[1,i,2],sink,sideways[1,i]);
for i:=1 to n-2 do for j:=1 to m-1 do add(id[i,j,1],id[i+1,j,2],sideways[i+1,j]);
for i:=1 to m-1 do add(source,id[n-1,i,1],sideways[n,i]);
// 竖边
for i:=1 to n-1 do add(source,id[i,1,1],vertical[i,1]);
for i:=1 to m-2 do for j:=1 to n-1 do add(id[j,i,2],id[j,i+1,1],vertical[j,i+1]);
for i:=1 to n-1 do add(id[i,m-1,2],sink,vertical[i,m]);
// 斜边
for i:=1 to n-1 do for j:=1 to m-1 do add(id[i,j,1],id[i,j,2],inclined[i,j]);
end;
begin
filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1);
filldword(dis,sizeof(dis) div 4,maxlongint div 843);
Construction; n:=sink;
// for i:=1 to tot do if i mod 2=1 then writeln(from[i],' ',reach[i]);
Dijkstra;
writeln(dis[n]);
end.
完结撒花!✿✿ヽ(゚▽゚)ノ✿