zoukankan      html  css  js  c++  java
  • 二部图最大匹配问题的求解 匈牙利算法

    #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 巩固

  • 相关阅读:
    Android实现《天女散花》效果(带源码)
    android 自定义(组合)控件 + 自定义控件外观
    Android 实现书籍翻页效果完结篇
    关于Button setOnClickListener 批量增加监听
    Android 小项目之解析如何获取SDCard 内存
    RadioGroup RadioButton 和 自定义对话框(自定义确定和取消)
    拒绝折腾——好用的EmEditor
    jquery ui 出现的诡异问题
    Google的PageRank算法浅析
    JQuery对数组的一些操作总结
  • 原文地址:https://www.cnblogs.com/Deng1185246160/p/3581066.html
Copyright © 2011-2022 走看看