D176 二分图最大匹配 匈牙利算法 CF1139E Maximize Mex
D176 二分图最大匹配 匈牙利算法 CF1139E Maximize Mex_哔哩哔哩_bilibili
CF1139E Maximize Mex - 洛谷 Problem - 1139E - Codeforces
有 n 个学生,m 个社团。每个学生属于一个社团。在接下来的 d 天里,每天会有一个人退团。
每天从每个社团中最多选出一个人,使得选出的人的潜力值集合 {pi} 的 mex 值最大。求出每天的最大 mex 值。
集合 S 的 mex 定义为不在 S 中的最小非负整数。例如,{0,1,1,2,4,5,9} 的 mex 是 3,{1,2,3} 的 mex 是 0。
思路
先不考虑删除人,怎么做?
每个人的属性是潜力值,每天每个社团中最多选出一个人,答案是选出的潜力值中的最小非负整数
把潜力值作为左部点,把社团作为右部点,连有向边,这样,一个社团最多只能选一条边
从 0 开始枚举潜力值,跑二分图最大匹配,遇到配对失败就终止,此数即答案
如果考虑删除人,相当于删除边,会破坏已有的匹配,不好进行
可以逆序思考,改为加边,每次加一条边,就找一次增广路,那么答案会单调不降

参考:D25【模板】二分图最大匹配 匈牙利算法 - 董晓 - 博客园
D175 二分图最大匹配 匈牙利算法 P1640 [SCOI2010] 连续攻击游戏 - 董晓 - 博客园
// 二分图 匈牙利算法 O(V*E) #include<bits/stdc++.h> using namespace std; const int N=5005; vector<int> e[N]; int n,m,d,a[N],b[N],c[N],f[N],ans[N]; int vis[N],match[N]; bool dfs(int u){ for(int v:e[u]){ if(vis[v]) continue; vis[v]=1; if(match[v]==-1 || dfs(match[v])){ match[v]=u; return 1; //配对成功 } } return 0; //配对失败 } int main(){ cin>>n>>m; //学生数 社团数 for(int i=1; i<=n; i++) scanf("%d",&a[i]); //潜力值 for(int i=1; i<=n; i++) scanf("%d",&b[i]); //社团编号 cin>>d; for(int i=1; i<=d; i++) scanf("%d",&c[i]); //离团学生 for(int i=1; i<=d; i++) f[c[i]]=1; //离团学生打标记 for(int i=1; i<=n; i++)if(!f[i]){ //枚举没有离团的学生 if(a[i]>m) continue; //潜力值>社团数,不会成为答案 e[a[i]].push_back(b[i]); //潜力值→社团编号 } memset(match,-1,sizeof(match)); //因为有0点,初始化为-1 for(int i=d; i; i--){ //倒序加边 for(int j=ans[i+1]; j<=m; j++){ //枚举潜力值 memset(vis,0,sizeof(vis)); if(!dfs(j)){ans[i]=j; break;} //潜力值中断,记录答案 } if(a[c[i]]>m) continue; //潜力值>社团数,不会成为答案 e[a[c[i]]].push_back(b[c[i]]); //潜力值→社团编号 } for(int i=1; i<=d; i++) printf("%d\n",ans[i]); return 0; }
浙公网安备 33010602011771号