算法的具体描述请看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),稍微加快了一点速度。