二分图匹配

匈牙利算法   

 https://blog.csdn.net/c20180630/article/details/70175814

增广路径

增广路径的定义:设M为二分图G已匹配边的集合,若P是图G中一条连通两个未匹配顶点的路径(P的起点在X部,终点在Y部,反之亦可),并且属M的边和不属M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。 
增广路径是一条“交错轨”。也就是说, 它的第一条边是目前还没有参与匹配的,第二条边参与了匹配,第三条边没有..最后一条边没有参与匹配,并且起点和终点还没有被选择过,这样交错进行,显然P有奇数条边

由增广路的定义可以推出下述三个结论:

  1. P的路径长度必定为奇数,第一条边和最后一条边都不属于M,因为两个端点分属两个集合,且未匹配。
  2. P经过取反操作可以得到一个更大的匹配M’。
  3. M为G的最大匹配当且仅当不存在相对于M的增广路径。

匈牙利算法

算法轮廓:

    1. 置M为空
    2. 找出一条增广路径P,通过取反操作获得更大的匹配M’代替M
    3. 重复2操作直到找不出增广路径为止

模板题hdu2063

#include<bits/stdc++.h>
using namespace std;
const int N=550;
int k,m,n,cnt;
bool vis[N];
int ma[N],last[N];
struct orz{
    int v,nex;}e[N*4];
void add(int x,int y)
{
    cnt++;
    e[cnt].v=y;
    e[cnt].nex=last[x];
    last[x]=cnt;
}
bool found(int x)
{
    for (int i=last[x];i;i=e[i].nex)
    {
        if (!vis[e[i].v])
        {
            int v=e[i].v;
            vis[v]=1;
            if (!ma[v]||found(ma[v]))
            {
                ma[v]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    while (scanf("%d",&k)&&k)
    {
        scanf("%d%d",&m,&n);
        memset(ma,0,sizeof(ma));
        memset(e,0,sizeof(e));
        memset(last,0,sizeof(last));
        cnt=0;
        int x,y;
        for (int i=1;i<=k;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        int ans=0;
        for (int i=1;i<=m;i++)
        {
            memset(vis,0,sizeof(vis));
            if (found(i)) ans++;
        }
        printf("%d\n",ans);
    }
}
hdu2063

 KM算法

https://blog.csdn.net/sixdaycoder/article/details/47720471

Kuhn-Munkras算法(即KM算法)流程:

  1. 初始化可行顶标的值 (设定lx,ly的初始值)
  2. 用匈牙利算法寻找相等子图的完备匹配
  3. 若未找到增广路则修改可行顶标的值
  4. 重复(2)(3)直到找到相等子图的完备匹配为止

模板题hdu2255

#include<bits/stdc++.h>
using namespace std;
const int N=550;
const int INF=0x3f3f3f3f;
int k,m,n,cnt;
bool visx[N],visy[N];
int ma[N],slack[N],lx[N],ly[N],G[N][N];
bool found(int x)
{
    visx[x]=1;
    for (int y=1;y<=n;y++)
    {
        if (!visy[y])
        {
            int now=lx[x]+ly[y]-G[x][y];
            if (now==0)
            {
                visy[y]=1;
                if (ma[y]==-1||found(ma[y]))
                {
                    ma[y]=x;
                    return 1;
                }
            }
            else slack[y]=min(slack[y],now);
        }
    }
    return 0;
}
void KM()
{
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++) slack[j]=INF;
        while(1)
        {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if (found(i)) break;
            int minm=INF;
            for (int j=1;j<=n;j++)
            if (!visy[j]) minm=min(minm,slack[j]);

            for (int j=1;j<=n;j++) if (visx[j]) lx[j]-=minm;
            for (int j=1;j<=n;j++)
                if (visy[j]) ly[j]+=minm;
                else slack[j]-=minm;
        }
    }
}
void solve()
{
    memset(ma,-1,sizeof(ma));
    memset(ly,0,sizeof(ly));
    for (int i=1;i<=n;i++)
    {
        lx[i]=-INF;
        for (int j=1;j<=n;j++)
        lx[i]=max(lx[i],G[i][j]);
    }
    KM();
}
int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
        scanf("%d",&G[i][j]);
        solve();
        int ans=0;
        for (int i=1;i<=n;i++)
        if (ma[i]!=-1) ans+=G[ma[i]][i];
        printf("%d\n",ans);
    }
}
hud2255

 

posted @ 2018-05-10 21:45  特特w  阅读(165)  评论(0编辑  收藏  举报