二分图匹配——匈牙利算法&&KM算法

二分图

1.1何为二分图

二分图是指可以把结点集分成两部分X和Y,使得每条边恰好一个端点在X,另一个端点在Y

1.2二分图匹配

完美匹配:每个点都被匹配到
完备匹配:二分图中X中的每一个顶点都与Y部中的一个顶点匹配,或者Y部中的每一个顶点也与X部中的一个顶点匹配,则该匹配为完备匹配。

1.二分图的最大基数匹配,主要针对无权图,需要求出包含边数最多的匹配;可用前面介绍的Edmonds-Karp||Dinic算法求解,增加一个超级源点s和超级汇点t,从源点到X各个点连接一条容量为1的有向边,从Y各个点到汇点t连接一条容量为1的有向边,将原图原本存在的边容量设置为1,然后跑最大流即可,但是这里我们用匈牙利算法。
2.二分图的最佳匹配:带权二分图的权值最大的完备匹配称为最佳匹配。这里我们用KM算法解决。
3.要求求出边权最大的匹配,对边数不做要求,将原图中所有边的费用设为权值的相反数,其他边费用为0,然后跑一遍最小费用最大流,记录流量为0,1,2,3…是的最小费用流,求得最小然后取反即可。

1.2.1匈牙利算法

匈牙利算法原理

此部分附上讲解更详细的链接https://blog.csdn.net/C20180630/article/details/70175814

匈牙利算法模板

时间复杂度O(nm)

const int INF=1<<30;
int vis[maxn];  //记录当前结点有没有被访问过
int visx[maxn];  //记录X中的结点i当前与谁匹配
int visy[maxn];	//记录Y中的结点i当前与谁匹配


bool dfs(int u){
    for(int i=0;i

1.2.2KM算法

KM算法模板

时间复杂度为O(n^3)

int visx[maxn];
int visy[maxn];
int linkx[maxn];
int linky[maxn];
int wx[maxn];
int wy[maxx];	//顶点的匹配值
int dis[maxn][maxn]; //记录边的权值

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

KM算法代码转载自https://blog.csdn.net/c20180630/article/details/71080521

你可能感兴趣的:(图论算法)