[CF1139 E] Maximize Mex 解题报告 (二分图匹配)

本文解析了CodeForces上的一道题目E,涉及到mex值、二分图和匈牙利算法。通过构建二分图,左侧为能力值,右侧为社团,实现动态匹配求解每天的最大mex值。
interlinkage:

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

description:

有$n$个学生,$m$个社团,每个学生有一个能力值,属于一个社团,在接下来的$d$天里,每天会有一个人退出所在的社团。

每天从每个社团中选出最多一个人组成能力值集合${p_i}$使得其$mex$最大。求出每天的最大$mex$值

solution:
  • $mex$经常与二分图模型相关;
  • 若答案为$t$,每一个小于$t$的能力值都对应一个提供它的社团。由此构造二分图,左侧是能力值,右侧是社团。若社团$c_i$存在一个学生能力值为$p_i$,那么$p_i$向$c_i$连边;
  • 这样跑匈牙利就是了;
  • 但是注意到学生是在动态变化的,随着天数的变化学生不断减少,我们要对二分图实行删边操作。但是匈牙利算法是不支持删边的;
  • 于是我们从最后一天开始倒着来,每天加边,这样的话答案就是非严格单调增的;
  • 加边不会影响之前的匹配,倒序输出即可;
code:
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;

const int N=1e4+15;
int n,m,tot;
int head[N<<1],a[N],b[N],c[N],used[N],match[N],ans[N];
struct EDGE
{
    int to,nxt;
}edge[N<<1];
void add(int u,int v)
{
    edge[++tot]=(EDGE){v,head[u]};
    head[u]=tot;
}
inline int read()
{
    char ch=getchar();int s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
int find(int x)
{
    if (used[x]) return 0;
    used[x]=1;
    for (int i=head[x];i;i=edge[i].nxt)
    if (match[edge[i].to]==-1||find(match[edge[i].to]))
    {
        match[edge[i].to]=x;
        return 1;
    }
    return 0;
}
int main()
{
    memset(match,-1,sizeof(match));
    n=read();m=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=n;i++) b[i]=read();
    int q=read();
    for (int i=1;i<=q;i++) c[i]=read(),used[c[i]]=1;
    for (int i=1;i<=n;i++) if (!used[i]) add(a[i],b[i]);
    int t=0;
    for (int i=q;i>=1;i--)
    {
        memset(used,0,sizeof(used));
        while (find(t))
        {
            ++t;
            memset(used,0,sizeof(used));
        }
        ans[i]=t;
        add(a[c[i]],b[c[i]]);
    }
    for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/xxzh/p/10698945.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值