二分图匹配的H-K算法

时间:2022-09-04 19:59:42

        算法的具体描述请看http://chenhaifeng.blog.edu.cn/2007/91117.html,我只是来贴代码的。

        http://blog.csdn.net/emoizhang/article/details/8004502这里讲的比我详细(虽然都是废话),但他的代码比我的慢。

【题目描述】

给一个有向无环图,求最小链覆盖

【输入格式】

第一行两个数nm,分别表示地图的点数和边数,接下来m行,每行两个数uv,表示有一条从点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),稍微加快了一点速度。