匈牙利算法

匈牙利算法

本文参考了大牛博客:https://www.byvoid.com/blog/hungary/

设G=(V,E)是一个无向图。如顶点集V可分割为两个互不相交的子集V1,V2之
选择这样的子集中边数最大的子集称为图的最大匹配问题(maximal matching problem)
如果一个匹配中,|V1|<=|V2|且匹配数|M|=|V1|则称此匹配为完全匹配,也称作完备匹配。特别的当|V1|=|V2|称为完美匹配。
 
图1:
M-交错路:p是G的一条通路,如果p中的边为属于M中的边与不属于M但属于G中的边交替出现,则称p是一条M-交错路。如:路径(x1,y1,x2,y2)。
M-饱和点:对于v∈V(G),如果v与M中的某条边关联,则称v是M-饱和点,否则称v是非M-饱和点。如x1,y1,x3,y2都属于M-饱和点,而其它点都属于非M-饱和点。
M-可增广路:p是一条M-交错路,如果p的起点和终点都是非M-饱和点,则称p为M-可增广路。如(x2,y1,x1,y3)。(不要和流网络中的增广路径弄混了)
匈牙利算法的思路就是寻找可增广路,每找到一条,匹配数加1.
代码:
#include <stdio.h>
#include <string.h>

#define N 10000

int cnt, head[N], used[N], mat[N], covered[N];//mat[i]的值表示与yi 配对的集合x中的某一结点,covered[i]表示结点xi 是否已经于集合y中的某一结点配对
//每次寻找增广路的时候,从集合x未配对的结点开始,依次遍历集合x。
int s, r, c, matches;
struct node2
{
    int next, to;
}edge[N * 2];

void init()
{
    memset(head, 0, sizeof(head));
    memset(used, 0, sizeof(used));
    memset(mat, 0, sizeof(mat));
    memset(covered, 0, sizeof(covered));
    cnt = matches = 0;
}

void conn(int from, int to)
{
    cnt++;
    edge[cnt].next = head[from];
    edge[cnt].to = to;
    head[from] = cnt;
}

bool crosspath(int i)
{
    for (int j = head[i]; j; j = edge[j].next)
    {
        int end = edge[j].to;
        if (!used[end])
        {
            used[end] = 1;
            if (mat[end] == 0 || crosspath(mat[end]))
            {
                covered[mat[end]] = 0;
                mat[end] = i;
                covered[i] = 1;
                return true;
            }
        }
    }
    return false;
}
void hungry()
{
    int i;
    for (i = 1; i <= r; i++)
    {
        used[i] = 1;
        if (!covered[i] && crosspath(i))
            matches++;    
        memset(used, 0, sizeof(used));
    }    
    printf("%d\n", matches);    
}

int main()
{
    int u, v, i;
    init();
    scanf("%d%d%d", &s, &r, &c);
    for (i = 0; i < s; i++)
    {
        scanf("%d%d", &u, &v);
        conn(u, v);
    }
    hungry();
    return  0;
}
下面描述是如何寻找增广路的整个过程:
开始
 
x1->y1是一条增广路,对增广路取反
 
x2->y1->x1->y2是一条增广路,对这条增广路取反
x3->y1->x2不是一条增广路,
 
因为x3还可以到y2,所以
x3->y2->x1->y1->x2也不是一条增广路,
继续
x3->y2->x1->y3是一条增广路,即
取反得到
over。
 
 

posted on 2013-11-12 22:05  jec  阅读(311)  评论(0编辑  收藏  举报

导航