首先考虑建图,因为

每个男孩最多只愿意和个不喜欢的女孩跳舞,而每个女孩也最多只愿意和个不喜欢的男孩跳舞。

所以对于每个男孩女孩均要建一个辅助点,到该点的权值为,对于互相喜欢的男女孩相连,权值为,对于不喜欢的,则他们的辅助点相连,权值亦为

接下来考虑源点到男孩与女孩到汇点的权值情况。

1.如果权值小于等于答案,计最大流为,则满足

2.权值大于答案,则有

所以,我可以用遍历权值从的情况,得到答案,也可二分来做

坑点:忘记女孩也要满足小于等于

const int N = 2e4 + 86;

struct egdes
{
    int to, nxt, w;
} e[N * 2];
int hd[N * 2], cur[N * 2], tot = 1, st, en;
vi lv;
void add(int x, int y, int w)
{
    e[++tot] = (egdes){y, hd[x], w};
    hd[x] = tot;
}

int bfs()
{
    lv.assign(N, 0);
    memcpy(cur, hd, sizeof(hd));
    queue<int> q;
    q.push(st);
    lv[st] = 1;
    while (!q.empty())
    {
        int p = q.front();
        q.pop();
        for (int eg = hd[p]; eg; eg = e[eg].nxt)
        {
            int to = e[eg].to, vol = e[eg].w;
            if (vol && !lv[to])
            {
                lv[to] = lv[p] + 1;
                q.push(to);
            }
        }
    }
    return lv[en];
}

int dfs(int ss, int flow)
{
    if (ss == en)
        return flow;
    int r = flow;
    for (int eg = cur[ss]; eg && r; eg = e[eg].nxt)
    {
        cur[ss] = eg;
        int to = e[eg].to, vol = e[eg].w;
        if (vol && lv[to] == lv[ss] + 1)
        {
            int c = dfs(to, min(r, vol));
            r -= c;
            {
                e[eg].w -= c;
                e[eg ^ 1].w += c;
            }
        }
    }
    return flow - r;
}
int n, k;
vi rim[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> k;
    st = 6 * n + 86, en = st + 1;
    f(j, 1, n)
    {
        string s;
        cin >> s;
        //if(s.length()!=n)cout<<s.length();
        f(i, 1, n)
        {
            if (s[i - 1] == 'Y')
                rim[j].pb(i);
            else
                rim[j + n].pb(i);
        }
    }
    int l=0,r=n;
    while (l<r)
    {
        memset(hd, 0, sizeof(hd));
        tot = 1;
        int mid=(l+r+1)>>1;
        f(i, 1, n)
        {
            add(st, i, mid);
            add(i, st, 0);
            add(i, i + 2 * n, k);
            add(i + 2 * n, i, 0);
            add(i+4*n,i+n,k);
            add(i+n,i+4*n,0);
            add(i + n, en, mid);
            add(en, i + n, 0);
            for (auto it : rim[i])
            {
                add(i, it + n, 1);
                add(it + n, i, 0);
            }
            for (auto it : rim[i + n])
            {
                add(i + 2 * n, it +4* n, 1);
                add(it + 4*n, i + 2 * n, 0);
            }
        }
        LL ans = 0;
        while (bfs())
        {
            ans += dfs(st, 3e8);
        }
        if (mid * n == ans)
        {
            l=mid;
        }
        else r=mid-1;
    }
    cout <<l;
    return 0;
}
此文章已被阅读次数:正在加载...更新于