KM算法模板

来源:互联网 发布:个股龙虎榜数据 编辑:程序博客网 时间:2024/05/19 18:17

模板:

O(n^4)

const int  maxn=1005;const int INF=1e9;bool sx[maxn], sy[maxn];int match[maxn],lx[maxn], ly[maxn];int n, m, d;int g[maxn][maxn];int sum;//n:左集元素个数; m:右集元素个数// g[i][j] 代表i到j的边权bool dfs (int u){    int v; sx[u] = true;    for (v = 1; v <=m; v++)    {        if (!sy[v] && lx[u]+ly[v]==g[u][v])        {            sy[v] = true;            if (match[v] == -1 || dfs (match[v]))            {                match[v] = u;                return true;            }        }    }    return false;}void KM (){    int i, j, k, ans = 0;    memset (ly, 0, sizeof(ly));    for (i = 1; i <=n; i++)    {        lx[i] = -INF;        for (j = 1; j <=m; j++)            if (lx[i] < g[i][j])                lx[i] = g[i][j];    }    memset (match, -1, sizeof(match));    for (i =1; i <=n; i++)    {        while (1)        {            memset (sx, false, sizeof(sx));            memset (sy, false, sizeof(sy));            if (dfs (i))                break;            d = INF;            for (j =1; j <=n; j++)                if (sx[j])                    for (k =1;k<=m; k++)                        if (!sy[k])                            d = min (d,lx[j]+ly[k]-g[j][k]);            for (j =1; j <=n; j++)                if (sx[j])                    lx[j] -= d;            for (j =1; j <=m; j++)                if (sy[j])                    ly[j] += d;        }    }    for (i = 1; i <= m; i++)        if (match[i] !=-1&&g[match[i]][i]!=-INF)            ans += g[match[i]][i];    printf("%d\n",ans);}

O(n^3)

const int maxn=1005;int g[maxn][maxn];bool visitx[maxn], visity[maxn];int lx[maxn], ly[maxn];int slack[maxn];int match[maxn];int n,m;bool Hungary(int u) //匈牙利算法{    visitx[u] = true;    for(int i = 1; i <= n; ++i)    {        if(visity[i])            continue;        if(lx[u] + ly[i] == g[u][i])        {            visity[i] = true;            if(match[i] == -1 || Hungary(match[i]))            {                match[i] = u;                return true;            }        }        else //不在相等子图            slack[i] = min(slack[i], lx[u] + ly[i] - g[u][i]);    }    return false;}void KM(){    int temp;memset(match, -1, sizeof(match));    memset(lx, 0, sizeof(lx)); //初始化顶标    memset(ly, 0, sizeof(ly)); //ly[i]为0    for(int i = 1; i <= n; ++i) //lx[i]为权值最大的边        for(int j = 0; j <= m; ++j)            lx[i] = max(lx[i], g[i][j]);    for(int i = 1; i <= n; i++) //对n个点匹配    {        for(int j = 1; j <= n; j++)            slack[j] = INT_MAX;        while(1)        {            memset(visitx, false, sizeof(visitx));            memset(visity, false, sizeof(visity));            if(Hungary(i)) //匹配成功                break;            else //匹配失败,找最小值            {                temp = INT_MAX;                for(int j = 1; j <= n; j++)                    if(!visity[j])                        if(temp > slack[j])                            temp = slack[j];                for(int j = 1; j <= n; j++) //更新顶标                {                    if(visitx[j])                        lx[j] -= temp;                }                for(int j=1;j<=m;++j)                {                   if(visity[j])                        ly[j] += temp;                    else                        slack[j] -= temp;                }            }        }    }int ans = 0;    for(int i = 1; i <= m; ++i) //权值相加        ans += g[match[i]][i];    printf("%d\n", ans);}


0 0
原创粉丝点击