演算法的具體描述請看http://chenhaifeng.blog.edu.cn/2007/91117.html,我只是來貼代碼的。
http://blog.csdn.net/emoizhang/article/details/8004502這裡講的比我詳細(雖然都是廢話),但他的代碼比我的慢。
【題目描述】
給一個有向非循環圖,求最小鏈覆蓋
【輸入格式】
第一行兩個數n、m,分別表示地圖的點數和邊數,接下來m行,每行兩個數u、v,表示有一條從點u到點v的有向邊。
【資料範圍】
n<=200000,m<=500000
【題解】
將每個點拆成兩個點,求最大匹配,答案即為點數減去最大匹配數。由於資料很大,所以需要使用HK演算法。
Code:
program maze;type int=longint;var i,j,k,m,n,x,y,tot,ans,l,r:int; ne,t:array[1..500100]of int; h,link,d,q:array[1..401000]of int; visited,v:array[1..201000]of boolean;procedure prepare;begin for i:=1 to n do begin j:=h[i]; while j<>0 do begin k:=t[j]; if link[k]=0 then begin link[k]:=i;inc(ans); v[i]:=true;break; end; j:=ne[j]; end; end;end;function bfs:boolean;begin fillchar(d,sizeof(d),$FF); l:=0;r:=0;bfs:=false; for i:=1 to n do if not v[i]then begin d[i]:=0;inc(r);q[r]:=i; end; if l=r then exit; repeat inc(l);i:=q[l];j:=h[i]; while j<>0 do begin k:=t[j];m:=link[k]; if m=0 then bfs:=true else if d[m]=-1 then begin d[m]:=d[i]+1;inc(r);q[r]:=m; end; j:=ne[j]; end; until l=r;end;function dfs(x:int):boolean;var j,k:int;begin j:=h[x]; while j<>0 do begin k:=t[j]; if(link[k]=0)or((d[link[k]]=d[x]+1)and(dfs(link[k])))then begin link[k]:=x;exit(true); end; j:=ne[j]; end; exit(false);end;begin assign(input,'maze.in');reset(input); assign(output,'maze.out');rewrite(output); read(n,m); for i:=1 to m do begin read(x,y); inc(tot);t[tot]:=y+n; ne[tot]:=h[x];h[x]:=tot; end; ans:=0; prepare; while bfs do for i:=1 to n do if(not v[i])and(dfs(i))then begin v[i]:=true;inc(ans); end; write(n-ans); close(input);close(output);end.
在具體的實現時,我先貪心了一個初始匹配(prepare),稍微加快了一點速度。