Codeforces Round #548 (Div. 2) E 二分图匹配(新坑) or 网络流 + 反向处理

https://codeforces.com/contest/1139/problem/E

题意

有n个学生,m个社团,每个学生有一个(p_i)值,然后每个学生属于(c_i)社团,
有d天,每天首先随机去除一个人,然后再从每个社团挑选一个学生(假如社团没有学生就跳过这个社团),使得这些学生组成的集合的mex值最大,输入每天的mex值

题解

  • 假如这道题发现是二分图匹配就很好做
  • 左边用(p_i)建点,右边用(c_i)建点,(p_i)从小到达和源点连边,然后跑个二分图匹配or最大流,直到没有新的匹配,就在中间加边
  • 倒着处理,每次加边进去(技巧)

代码

#include<bits/stdc++.h>
#define MAXN 5005

using namespace std;
int n,m,i,j,link[MAXN],p[MAXN],c[MAXN],d,k[MAXN],vi[MAXN],ans[MAXN];
int del[MAXN];
vector<int>mp[MAXN];
int match(int u){
	for(auto i:mp[u]){
		if(!vi[i]){
			vi[i]=1;
			if(link[i]==-1||match(link[i])){
				link[i]=u;
				vi[i]=0;
				return 1;
			}
			vi[i]=0;
		}
	}
	return 0;
}
int main(){
	cin>>n>>m;
	memset(link,-1,sizeof(link));
	for(i=1;i<=n;i++)cin>>p[i];
	for(i=1;i<=n;i++)cin>>c[i];
	cin>>d;
	for(i=1;i<=d;i++){cin>>k[i];del[k[i]]=1;}
	for(i=1;i<=n;i++)if(!del[i]){mp[p[i]].push_back(c[i]);}
	j=0;
	for(i=d;i>=1;i--){
		int id=k[i];
		for(;j<5000;j++){
			//memset(vi,0,m*sizeof(int));
			if(!match(j))break;
		}
		ans[i]=j;
		mp[p[id]].push_back(c[id]);
	}
	for(i=1;i<=d;i++)cout<<ans[i]<<endl;
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/10631241.html