专题 - 匈牙利算法

二分图最大匹配之匈牙利算法

如此之菜的笔者现在才学会

板子题 - Luogu P3386 【模板】二分图最大匹配
挂个链接 - https://www.luogu.com.cn/prob...
题面 - 给定一个二分图,其左部点的个数为n,右部点的个数为m,边数为 e,求其最大匹配的边数

Now,让我们开始学习匈牙利算法

匈牙利是用增广路求最大匹配的算法
增广路的定义,若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径,M为G的最大匹配当且仅当不存在M的增广路径

红红火火恍恍惚惚
你是不是很懵呀,是不是感觉如此高大上,其实非常简单,笔者是故意说的这么复杂的,换一种说法你就明白了

笔者就用牛和牛栏来解释吧(其实本来想用撮合情侣来解释的)

现在有n头牛,m个牛栏,牛只能在它喜欢的牛栏中且一个牛栏一头牛,告诉你每头牛喜欢哪些牛栏,问你最多能安排多少对牛和牛栏

要你干什么你明白了吧,现在就是怎么做的问题了

现在开讲匈牙利算法(这次是正经的)

举个栗子吧,这样会清晰一些

专题 - 匈牙利算法_第1张图片

这是题目给你的条件

下面就要利用这些条件进行匈牙利算法了

先看到牛1,去找它喜欢的牛栏有没有空着的
发现它喜欢的牛栏1空着,那就占下牛栏1

专题 - 匈牙利算法_第2张图片

牛1有牛栏了,下面看牛2,再去找牛2喜欢的牛栏有没有空着的
发现它喜欢的牛栏2空着,那就占下牛栏2

专题 - 匈牙利算法_第3张图片

接着看牛3,去找牛3喜欢的牛栏有没有空着的
它喜欢的牛栏没有空位
这时候他就要让其它的牛设法给腾出自己想要的牛栏,这是个递归的过程
首先找到牛3喜欢的牛栏1现在的主人牛1手上,于是便让牛1给它腾位置
牛1只好去找别的位置,发现自己喜欢的牛栏没有也没有空位
于是它找到牛栏2现在的主人牛2,让牛2给自己腾位置
牛2发现自己还有牛栏3空着,便占下牛栏3,开始递归回溯
牛2把牛栏2腾给了牛1,牛1占下牛栏2
牛1把牛栏1腾给了牛3,牛3占下牛栏1

专题 - 匈牙利算法_第4张图片

最后是牛4,去找牛4喜欢的牛栏又没有空着的
发现没有,便递归请其它牛帮它腾牛栏,结果腾不出来(递归过程可以自己尝试梳理一下)

于是最终答案就是这样

专题 - 匈牙利算法_第5张图片

这样的递归如何用程序实现呢
请看下方(我叫它DFS,似乎更多是叫Find)

bool DFS(int x){
    vis[x]=1; //标记已访问过该点
    for(int i=0; i

一定要记得判段重复啊(笔者就在这上面被坑了,直接死循环爆栈)

OK,这就基本结束啦~o(* ̄▽ ̄*)o

最后照例奉上完整程序和精心设计的注解

//Luogu P3386 [普及+/提高] - 二分图最大匹配 
//https://www.luogu.com.cn/problem/P3386
//匈牙利算法 

#include
using namespace std;

int have[505]={0}; //记录牛栏的主人 
int vis[505]; //标记已访问 
vector v[505]; //存放牛喜欢的牛栏 

bool DFS(int x){
    vis[x]=1; //标记已访问过该点
    for(int i=0; i> N >> M >> E;
    
    for(int i=1; i<=E; i++){
        int a, b;
        cin >> a >> b;
        v[a].push_back(b);
    }
    
    for(int i=1; i<=N; i++){
        for(int j=1; j<=N; j++)
            vis[j]=0; //vis[]记得每次都要清零 
        if(DFS(i))
            ans++;
    }

    cout << ans;
    
    return 0;
}

最后的最后,有问题欢迎在下方评论区提出呀~

你可能感兴趣的:(c++)