二分图匹配——匈牙利算法和KM算法模板

二分图匹配详解:https://blog.csdn.net/c20180630/article/details/70175814  作者:C20180630_zjf

匈牙利算法:

//伪代码
bool dfs(int u)//寻找从u出发的增广路径
{
    for each v∈u的邻接点
        if(v未访问){
            标记v已访问;
            if(v未匹配||dfs(cy[v])){
                cx[u]=v;
                cy[v]=u; 
                return true;//有从u出发的增广路径
            }
        }
    return false;//无法找到从u出发的增广路径
}
//代码
bool dfs(int u){
    for(int v=1;v<=m;v++)
        if(t[u][v]&&!vis[v]){
            vis[v]=1;
            if(cy[v]==-1||dfs(cy[v])){
                cx[u]=v;cy[v]=u;
                return 1;
            }
        }
    return 0;
}
void maxmatch()//匈牙利算法主函数
{
    int ans=0;
    memset(cx,0xff,sizeof cx);
    memset(cy,0xff,sizeof cy);
    for(int i=0;i<=nx;i++) 
        if(cx[i]==-1)//如果i未匹配
        { 
            memset(visit,false,sizeof(visit)) ; 
            ans += dfs(i); 
        }
    return ans ;
} 

KM算法:

bool dfs(int s) //匈牙利算法找增广路径
{
    visx[s]=1;
    for(int i=1;i<=cnty;i++) 
        if(!visy[i]){
            int t=wx[s]+wy[i]-dis[s][i];
            if(t==0) {
                visy[i]=1;
                if(linky[i]==0||dfs(linky[i])){
                    linkx[s]=i,linky[i]=s;
                    return true;
                }
            }
            else if(t>0)  //找出边权与顶标和的最小的差值
            {
                if(t<minz)minz=t;
            }
        }
    return false;
}
void km()
{
    memset(linkx,0,sizeof linkx); //linkx[i]表示与X部中点i匹配的点
    memset(linky,0,sizeof linky);
    for(int i=1;i<=cntx;i++){
        while(1){
            minz=INF;
            memset(visx,0,sizeof visx);
            memset(visy,0,sizeof visy);
            if(dfs(i))break;
            for(int j=1;j<=cntx;j++)  //将交错树中X部的点的顶标减去minz
            if(visx[j])wx[j]-=minz;
            for(int j=1;j<=cnty;j++) //将交错树中Y部的点的顶标加上minz
            if(visy[j])wy[j]+=minz;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43821265/article/details/87534795