D25【模板】二分图最大匹配 匈牙利算法
D25【模板】二分图最大匹配 匈牙利算法_哔哩哔哩_bilibili
设 G 为二分图,若在 G 的子图 M 中,任意两条边都没有公共节点,那么称 M 为 G 的一组匹配,包含边数最多的一组匹配称为二分图最大匹配
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路
增广路:从一个未匹配点出发,走交替路,若能到达另一个未匹配点,则这条交替路称为增广路,例如 3→5→1→4→2→7
发现:增广路上的非匹配边比匹配边多一条。如果倒过来走,匹配边比非匹配边多一条,即找到一次增广路就会使匹配边增加 1 条

匈牙利算法
枚举所有左部点,搜索增广路来增加匹配边,找不到增广路时,达到最大匹配

第 1 轮,男生 1 选了女生 1,配对成功
第 2 轮,男生 2 选女生 1,男生 1 退让选女生 2,配对成功
第 3 轮,男生 3 选女生 2,男生 1 退让选女生 1,男生 2 退让选女生 4,配对成功
第 4 轮,男生 4 选女生 4,男生 2 退让选女生 1,男生 1 退让选女生 2,男生 3 退让失败,返回男生 1 选女生 3,配对成功
第 5 轮,男生 5 选女生 3,男生 1 退让选女生 1,男生 2 退让选女生 4,男生 4 退让失败,返回男生 1 选女生 2,男生 3 退让失败,返回男生 5 无女可配,配对失败
因为至多需要枚举 𝑂(|𝑉|)
个左部点 各一次,所以,算法总的时间复杂度为 𝑂(|𝑉||𝐸|)
// 二分图 匈牙利算法 O(V*E) #include<bits/stdc++.h> using namespace std; const int N=505; vector<int> e[N]; int n,m,k,ans; int vis[N],match[N]; //女生参与,配对信息 bool dfs(int u){ for(auto v:e[u]){ if(vis[v]) continue; //若女生v已参与这一轮试配,就跳过 vis[v]=1; //记录女生v参与这一轮试配 if(!match[v] || dfs(match[v])){ //若女生v没配对 或 女生v的男友可以另选她人 match[v]=u; //记录v的男友是u return 1; //返回配对成功 } } return 0; //返回配对失败 } int main(){ cin>>n>>m>>k; for(int i=0,a,b;i<k;i++)cin>>a>>b,e[a].push_back(b); //男连女 for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); //女生皆可参与这一轮试配 if(dfs(i)) ans++; //若男生i配对成功,ans+1 } cout<<ans; }
// 二分图 匈牙利算法 O(V*E) 优化:去掉 memset #include<bits/stdc++.h> using namespace std; const int N=505; vector<int> e[N]; int n,m,k,t,ans; int vis[N],match[N]; //女生参与,配对信息 bool dfs(int u){ for(auto v:e[u]){ if(vis[v]==t) continue; //若女生v已参与第t轮试配,就跳过 vis[v]=t; //记录女生v参与第t轮试配 if(!match[v] || dfs(match[v])){ //若女生v没配对 或 女生v的男友可以另选她人 match[v]=u; //记录v的男友是u return 1; //返回配对成功 } } return 0; //返回配对失败 } int main(){ cin>>n>>m>>k; for(int i=0,a,b;i<k;i++)cin>>a>>b,e[a].push_back(b); //男连女 for(int i=t=1;i<=n;i++,t++)if(dfs(i)) ans++; //若男生i配对成功,ans+1 cout<<ans; }
浙公网安备 33010602011771号