匈牙利算法改进 之 队列优化寻找极大增广路径集 —— Hopcroft-Karp算法 【记录】

来源:互联网 发布:网络马甲是什么意思 编辑:程序博客网 时间:2024/06/10 11:09

算法求解:同匈牙利算法解决的问题,只不过优化了时间复杂度。

算法分析:增广sqrt(n)次,每次需要遍历边数m,时间复杂度——O(sqrt(n) * m)。


算法实现:

1,BFS寻找多条不相交的增广路径,找到极大增广路径集。在这个过程中,设置数组dx[]、dy[]建立X集、Y集的层次图,可以理解为维护距离标号。

(可能说法不恰当,这点同最大流Dinic算法里面BFS找一条增广路,只不过这里是找多条)。

2,然后就是原版匈牙利算法的匹配过程,只不过多出了层次图的判定。

3,一直BFS找极大增广路径集,若增广路不存在,跳出,算法结束。

可以证明最多BFS 寻找sqrt(n)次,就可以求得最大匹配。




代码:


#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN 5000+10using namespace std;int mx[MAXN], my[MAXN];//记录X和Y集元素的匹配点int dx[MAXN], dy[MAXN];//记录距离标号bool used[MAXN];//标记是否使用vector<int> G[MAXN];//存储二分图int n, m;//点数 边数int numx, numy;//记录X集元素个数 Y集元素个数int DFS(int u)//同匈牙利算法 多了层次图的判定{    for(int i = 0; i < G[u].size(); i++)    {        int v = G[u][i];        if(!used[v] && dy[v] == dx[u] + 1)        {            used[v] = true;            if(my[v] == -1 || DFS(my[v]))            {                my[v] = u;                mx[u] = v;                return 1;            }        }    }    return 0;}void HK_match(){    memset(mx, -1, sizeof(mx));    memset(my, -1, sizeof(my));    int ans = 0;    while(1)    {        bool flag = false;//标记是否找到可增广路径        memset(dx, 0, sizeof(dx));        memset(dy, 0, sizeof(dy));        queue<int> Q;        for(int i = 1; i <= numx; i++)            if(mx[i] == -1) Q.push(i);        while(!Q.empty())//寻找增广路        {            int u = Q.front(); Q.pop();            for(int i = 0; i < G[u].size(); i++)            {                int v = G[u][i];                if(!dy[v])                {                    dy[v] = dx[u] + 1;//感觉和 Dinic里面建立层次图很像                    if(my[v] == -1)//未匹配 说明找到增广路                    flag = true;                    else                    {                        dx[my[v]] = dx[u] + 1;                        Q.push(my[v]);                    }                }            }        }        if(!flag)//未找到增广路            break;        memset(used, false, sizeof(used));        for(int i = 1; i <= numx; i++)            if(mx[i] == -1)//没有匹配 就开始找匹配                ans += DFS(i);    }    printf("%d\n", ans);//若X、Y集没有详细划分,则numx = numy = n,最后结果除2。}int main(){    while(scanf("%d%d", &n, &m) != EOF)    {        getMap();//建图 用G存储        HK_match();//HK算法    }    return 0;}


0 0
原创粉丝点击