• [CF1139 E] Maximize 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
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    [省选联考 2020 A 卷] 魔法商店 (保序回归)
    【CSON原创】HTML5游戏框架cnGameJS开发实录(资源加载模块篇)
    Go语言核心36讲30
    Go语言核心36讲29
    Go语言核心36讲31
    Go语言核心36讲28
    Go语言核心36讲27
    Go语言核心36讲25
    Go语言核心36讲34
    Go语言核心36讲24
  • 原文地址:https://www.cnblogs.com/xxzh/p/10698945.html
Copyright © 2020-2023  润新知