D171【模板】二分图最大匹配 匈牙利算法 P2756 飞行员配对方案问题

D171【模板】二分图最大匹配 匈牙利算法 P2756 飞行员配对方案问题_哔哩哔哩_bilibili

 

P2756 飞行员配对方案问题 - 洛谷

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);
}

 

posted @ 2026-05-26 17:34  董晓  阅读(58)  评论(0)    收藏  举报