D171【模板】二分图最大匹配 匈牙利算法 P2756 飞行员配对方案问题
D171【模板】二分图最大匹配 匈牙利算法 P2756 飞行员配对方案问题_哔哩哔哩_bilibili
m 个外籍飞行员和 (n−m) 个英国飞行员,找出最多的飞行员配对方案,输出其中一种
思路
复习:D25【模板】二分图最大匹配 匈牙利算法 - 董晓 - 博客园
二分图最大匹配问题,建图时只需要连单向边(男连女),让男生去选女生

如果每次枚举男生,都用 $memset$ 清空 $vis$ 数组太浪费时间,数据规模到 $10^5$ 就会 TLE
第 1 种优化方法:可以用全局变量 $t$ 记录枚举的轮次,从而去掉 $memset$
对于当前第 $t$ 轮,每个女生的 $vis[\,]<t$,表示每个女生都可以参与第 $t$ 轮试配
第 1 轮 $t=1:1→5$,配对成功
第 2 轮 $t=2:2→5,1→6$,配对成功
第 3 轮 $t=3:3→5,2→6,1→7$,配对成功
第 4 轮 $t=4:4→7,1→5,3\;不让,1→6,2\;不让,1\;不让$,配对失败
枚举结束,$match[\,]$ 数组只记录最后一轮配对成功的结果,输出即可
第 2 种优化方法:把 int vis[N] 改成 bitset<N> vis,bitset 清空非常快,具体见后面代码
// 二分图 匈牙利算法 O(V*E) #include<bits/stdc++.h> using namespace std; const int N=105; 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>>m>>n; for(int a,b;;){ cin>>a>>b; if(a==-1)break; e[a].push_back(b); //男连女 }
for(int i=1;i<=m;i++){ memset(vis,0,sizeof(vis)); //女生皆可参与这一轮试配 if(dfs(i)) ans++; //若男生i配对成功,ans+1 } printf("%d\n",ans); for(int i=m+1;i<=n;i++)if(match[i]) printf("%d %d\n",match[i],i); }
// 二分图 匈牙利算法 O(V*E) 优化:去掉 memset #include<bits/stdc++.h> using namespace std; const int N=105; vector<int> e[N]; int n,m,k,ans; int t,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>>m>>n; for(int a,b;;){ cin>>a>>b; if(a==-1)break; e[a].push_back(b); //男连女 } for(int i=t=1;i<=m;i++,t++)if(dfs(i)) ans++; //若男生i配对成功,ans+1 printf("%d\n",ans); for(int i=m+1;i<=n;i++)if(match[i]) printf("%d %d\n",match[i],i); }
// 二分图 匈牙利算法 O(V*E) 优化:去掉 memset #include<bits/stdc++.h> using namespace std; const int N=105; vector<int> e[N]; int n,m,k,ans; int match[N]; //女生配对信息 bitset<N> vis; //各二进制位清空很快 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>>m>>n; for(int a,b;;){ cin>>a>>b; if(a==-1)break; e[a].push_back(b); //男连女 } for(int i=1;i<=m;i++){ vis=0; //清空bitset各位 ans+=dfs(i); //若男生i配对成功,ans+1 } printf("%d\n",ans); for(int i=m+1;i<=n;i++)if(match[i]) printf("%d %d\n",match[i],i); }
浙公网安备 33010602011771号