Hopcroft-karp 算法

来源:互联网 发布:知乎那些曾经轰动一时 编辑:程序博客网 时间:2024/05/16 12:38

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);}


0 0
原创粉丝点击