匈牙利算法优化


const int MAXN=550;// 最大点数
int bmap[MAXN][MAXN];//二分图
int cx[MAXN];//cx[i]表示左集合i顶点所匹配的右集合的顶点序号
int cy[MAXN]; //cy[i]表示右集合i顶点所匹配的左集合的顶点序号
int dis;
int n,m;
int dx[MAXN],dy[MAXN];  //dx表示到x的距离,dy表示到y的距离
int used[MAXN];        //在每次增广中是否使用i点
 
bool SearchPath()   //bfs寻找增广路集
{
    queue<int>Q;
    dis = INF;  //存每一次增广的距离
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=1;i<=n;i++)
    {
        if(cx[i]==-1)  将未遍历的节点入队,并初始化次节点距离为0
        {
            Q.push(i);
            dx[i] = 0;
        }
    }
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        if(dx[u]>dis)
            break;
        //取右边的节点
        for(int v=1;v<=m;v++)
        {
            if(bmap[u][v]&&dy[v]==-1)
            {
                dy[v] = dx[u] + 1;  //v的距离为u的对应距离+1
                if(cy[v]==-1)       //如果该点未匹配,增广路形成
                    dis = dy[v];
                else                //如果该点已匹配,那么接着往下搜
                {
                    dx[cy[v]] = dy[v] + 1;
                    Q.push(cy[v]);
                }
            }
        }
    }
    return dis!=INF;
}
 
bool DFS(int u)
{
    for(int v=1;v<=m;v++)
    {
        //如果该点没有被使用过,并且距离为上一节点+1
        if(!used[v]&&bmap[u][v]&&dy[v]==dx[u]+1)
        {
            used[v] = 1;  //标记使用过该点
            //如果该点已经被匹配了并且为最后一个匹配点,那么这条路径不是增广路,即这条路的结点已经匹配
            if(cy[v]!=-1&&dy[v]==dis)
                continue;
            if(cy[v]==-1||DFS(cy[v]))
            {
                cy[v]=u,cx[u]=v;
                return true;
            }
        }
    }
    return false;
}
 
int MaxMatch()
{
    int sum = 0;
    memset(cx,-1,sizeof(cx));
    memset(cy,-1,sizeof(cy));
    while(SearchPath()) //当存在增广路,继续松弛
    {
        memset(used,0,sizeof(used));   //每一次的右边的点是否用过
        for(int i=1;i<=n;i++)
        {
            if(cx[i]==-1&&DFS(i))    //如果当前这个点没连过,且能找到增宽路
                sum++;
        }
    }
    return sum;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值