Chinaunix首页 | 论坛 | 博客
  • 博客访问: 474185
  • 博文数量: 117
  • 博客积分: 3195
  • 博客等级: 中校
  • 技术积分: 1156
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-04 01:44
文章分类

全部博文(117)

文章存档

2012年(5)

2011年(5)

2010年(46)

2009年(61)

我的朋友

分类:

2009-09-25 21:51:12

二分图

G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(ij)所关联的两个顶点ij分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

 

二分匹配

G=E> M  E M中任何两边不相邻,则称M是为G中的匹配,若在M中再加任意一条边后,所得集合都不是匹配了,则M极大匹配,边数最多的匹配为最大匹配

e=vi vj  M,则称vivjM匹配。

对于任意的v VG),若存在边e M,使ev关联,则称vM-饱和点,否则M-非饱和点

G中每个顶点都是M-饱和点,则称MG中的完美匹配

G中在M和(E(G)-M)中交替取边的路径PM交错路径(增广路,交错轨),起点和终点都是M-非饱和点的交错路径称可增广轨

 

匈牙利算法

(1)       M为空

(2)       找出一条增广路径P,通过取反操作获得更大的匹配M’代替M(所谓取反操作就是本来属于M的边设成不属于M,不属于M的边设成属于M,这样匹配数就多了一个,如下图)

 

 
(3)       重复(2)操作,直到找不出增广路为止。

 


伪代码:

bool 寻找从k出发的对应项出的可增广路
{
    while (从邻接表中列举k能关联到顶点j)
    {
        if (j不在增广路上)
        {
            把j加入增广路;
            if (j是未盖点 或者 从j的对应项出发有可增广路)
            {
                修改j的对应项为k;
                则从k的对应项出有可增广路,返回true;
            }
        }
    }
    则从k的对应项出没有可增广路,返回false;
}
    
void 匈牙利hungary()
{
    for i->1 to n
    {
        if (则从i的对应项出有可增广路)
            匹配数++;
    }
    输出 匹配数;
}

来自某大牛博客:http://www.byvoid.com/blog/hungary/

里面还有详细图解


#include <stdio.h>
#include <string.h>
#include <conio.h>
#define MAX 102

int n, n1, match;
int g[MAX][MAX];
int mat[MAX];
bool used[MAX];

bool find(int k)
{
       for(int i=1; i<=g[k][0]; i++) //从邻接表中列举k能关联到的顶点j

    {
        int j = g[k][i];
        if(!used[j]) //j不在增广路上

        {
            used[j] = true; //j加入增广路

            if(mat[j] == 0 || find(mat[j]))
                //j是未盖点 或者 从j的对应项出发有可增广路

            {
                mat[j] = k; //跟j对应项为k

                return true; //从k的对应项出有可增广路
            }
        }
    }
    return false;
}

void hungary()
{
    for(int i=1; i<=n1; i++)
    {
        if(find(i)) //从i的对应项出有可增广路
            match++; //匹配数++
        memset(used, 0, sizeof(used));
    }
}

int main()
{
    int i, j;
    int a, b;
    freopen("in.txt", "r", stdin);
    scanf("%d%d", &n, &n1);
    while(scanf("%d%d", &a, &b) != EOF)
    {
        g[a][++g[a][0]] = b; //建邻接表
    }
    match = 0;
    hungary();
    printf("%d\n", match);
    getch();
    return 0;
}


阅读(857) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~