Hopcroft-karp 算法

Hopcroft-Karp算法

該算法由John.E.Hopcroft和Richard M.Karp於1973提出,故稱Hopcroft-Karp算法。時間複雜度O(n^0.5*m)


思路:

用bfs來找出多條不相交的最短增廣路,形成極大增廣路集,然後可以用匈牙利多路增廣。

bfs要找最短的增廣路,是因爲增廣路的長度能增加,他的匹配數也能增加,所以最短保證答案的準確。
每一階段找出來的最短增廣路都是相等的長度,後面越來越長。
也就是說,每次找出可以達到同樣長度的多條增廣路。

其實多路增廣的思路與最大流的dinic是一樣的


過程:

將點二分圖的點分成兩個點集x,y
首先從所有x的未匹配的點進行bfs,維護x,y距離標號dx,dy,如果y點是未匹配的點那麼就找到
一條最短增廣路,記錄當前長度,大於該長度的結束bfs,bfs完之後得到最短增廣路集,用匈牙利算法,

對所有允許弧(dy[v]==dx[u]+1)進行增廣。


模板:

/**dx[i]表示左集合i頂點的距離編號,dy[i]表示右集合i頂點的距離編號**/
/**mx[i]表示左集合頂點所匹配的右集合頂點序號,my[i]表示右集合i頂點匹配到的左集合頂點序號。**/
struct edge {
    int v,next;
}e[Mm];
int tot,head[Mn];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int mx[Mn],my[Mn],vis[Mn];
int dis;
int dx[Mn],dy[Mn];
int n,m;
bool searchp() {
    queue<int>q;
    dis=INF;
    CLR(dx,-1);
    CLR(dy,-1);
    for(int i=1;i<=n;i++) {
        if(mx[i]==-1) {
            q.push(i);
            dx[i]=0;
        }
    }
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        if(dx[u]>dis) break;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].v;
            if(dy[v]==-1) {
                dy[v]=dx[u]+1;
                if(my[v]==-1) dis=dy[v];
                else {
                    dx[my[v]]=dy[v]+1;
                    q.push(my[v]);
                }
            }
        }
    }
    return dis!=INF;
}
bool dfs(int u) {
    for(int i=head[u];~i;i=e[i].next) {
        int v=e[i].v;
        if(vis[v]||(dy[v]!=dx[u]+1)) continue;
        vis[v]=1;
        if(my[v]!=-1&&dy[v]==dis) continue;
        if(my[v]==-1||dfs(my[v])) {
            my[v]=u;
            mx[u]=v;
            return true;
        }
    }
    return false;
}
int maxMatch() {
    int res = 0;
    CLR(mx,-1);
    CLR(my,-1);
    while(searchp()) {
        CLR(vis,0);
        for(int i=1;i<=n; i++)
            if(mx[i] == -1 && dfs(i))
                res++;
    }
    return res;
}
void init() {
    tot=0;
    CLR(head,-1);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章