二部图最大匹配问题的求解 匈牙利算法

#define MAXN 10        //MAXN为表示X集合和Y集合顶点个数最大值的符号常量
int nx, ny;        //X和Y集合中顶点的个数
int g[MAXN][MAXN];    //邻接矩阵,g[i][j]为1表示Xi和Yj有边相连
int cx[MAXN] , cy[MAXN];    //cx[i]表示最终求得的最大匹配中与Xi匹配的Y顶点, cy[i]同理

 

DFS增广

//DFS算法中记录顶点访问状态的数组,mk[i] = 0表示未访问过,为1表示访问过
int mk[MAXN] ;

//从X集合中的顶点u出发,用深度优先的策略寻找增广路
//(这种增广路只能使当前的匹配数增加1)
int path( int u )
{
    for( int v = 0 ; v < ny ; v++ )        //考虑所有Yi顶点v
    {
        if( g[u][v] && !mk[v] )    //v与u邻接,且没有访问过
        {
            mk[v] = 1;    //访问v
            //如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到一条增广路
            if( cy[v] == -1 || path( cy[v] ) )    //注意如果前一个条件成立,则不会递归调用
            {
                cx[u] = v; //把v匹配给u
                cy[v] = u; //把u匹配给v
                return 1; //找到可增广路
            }
        }
    }
    return 0 ; //如果不存在从u出发的增广路
}
int MaxMatch( )    //求二部图最大匹配的匈牙利算法
{
    int res = 0;    //所求得的最大匹配
    memset( cx , 0xff , sizeof(cx) ) ; //从0匹配开始增广, 将cx和cy各元素初始化为-1
    memset( cy , 0xff , sizeof(cy) ) ;
    for( int i = 0 ; i <= nx ; i++ )
    {
        if( cx[i] == -1 ) //从每个未盖点出发进行寻找增广路
        {
            memset( mk , 0 , sizeof(mk) ) ;
            res += path(i) ; //每找到一条增广路,可使得匹配数加1
        }
    }
    return res;
}

 

用BFS增广

int pred[MAXN];        //是用来记录交错轨的,同时也用来记录Y集合中的顶点是否遍历过
int queue[MAXN];    //实现BFS搜索用到的队列(用数组模拟)
int MaxMatch( )
{
    int i, j, y;
    int cur, tail;    //表示队列头和尾位置的下标
    int res = 0;    //所求得的最大匹配数
    memset( cx , 0xff , sizeof(cx) );    //初始化所有点为未被匹配的状态
    memset( cy , 0xff , sizeof(cy) );
    for( i = 0; i < nx; i++ )
    {
        if( cx[i] != -1 )  continue;
        //对X集合中的每个未盖点i进行一次BFS找交错轨
        for( j = 0; j < ny; j++ )  pred[j] = -2;    //-2表示初始值
        cur = tail = 0; //初始化BFS的队列
        for( j = 0; j < ny; j++ )    //把i的邻接点顶都入队列
        {
            if( g[i][j] )
            {
                pred[j] = -1;  queue[tail++] = j;    //-1表示遍历到,是邻接顶点
            }
        }
        while( cur < tail )    //BFS
        {
            y = queue[cur];
            if( cy[y] == -1 )  break;    //找到一个未被匹配的点,则找到了一条交错轨
            cur++;
            //y已经被匹配给cy[y]了,从cy[y]出发,将它的邻接顶点入队列
            for( j = 0; j < ny; j++ )
            {
                if( pred[j] == -2 && g[cy[y]][j] )
                {
                    pred[j] = y;
                    queue[tail++] = j;
                }
            }
        }
        if( cur == tail )  continue;    //没有找到交错轨
        while( pred[y] > -1 )    //更改交错轨上匹配状态 
        {
            cx[ cy[ pred[y] ] ] = y;
            cy[y] = cy[ pred[y] ];
            y = pred[y];
        }
        cy[y] = i;  cx[i] = y;
        res++;    //匹配数加1
    }
    return res;
}

 

 

可通过zoj1654  zoj1364  zoj1140 巩固

posted @ 2014-03-04 20:19  哥的笑百度不到  阅读(516)  评论(0编辑  收藏  举报