我们可以贪心的考虑,就是尽量把小的覆盖完。我们把所有的点从小到大排序,然后直接二分覆盖前\(k\)个点,用网络流跑一下二分图求出最小链覆盖,然后就判断一下点数减去最小链有没有超过给定的人数
#include <bits/stdc++.h>
using namespace std;
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef pair<int, int> pii;
inline int read() {
    int sum = 0, fg = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1;
    for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    return fg * sum;
}
const int maxn = 500 + 10;
const int maxm = 5e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m;
namespace Dinic {
    int S, T;
    int Begin[maxn << 1], Next[maxm + (maxn << 2)], To[maxm + (maxn << 2)], w[maxm + (maxn << 2)], e;
    int d[maxn << 1], cur[maxn << 1];
    void init() {
        S = 0, T = m << 1 | 1, e = -1;
        memset(Begin, -1, sizeof Begin);
    }
    void add(int x, int y) {
        To[++e] = y, Next[e] = Begin[x], Begin[x] = e, w[e] = 1;
        To[++e] = x, Next[e] = Begin[y], Begin[y] = e, w[e] = 0;
    }
    int bfs() {
        memset(d, 0, sizeof d); d[S] = 1;
        queue<int> q; q.push(S);
        while (!q.empty()) {
            int now = q.front(); q.pop();
            for (int i = Begin[now]; i + 1; i = Next[i]) {
                int son = To[i];
                if (!d[son] && w[i] > 0) {
                    d[son] = d[now] + 1; q.push(son);
                }
            }
        }
        return d[T];
    }
    int dfs(int now, int flow) {
        if (now == T) return flow;
        int sum = 0;
        for (int &i = cur[now]; i + 1; i = Next[i]) {
            int son = To[i];
            if (w[i] > 0 && d[son] == d[now] + 1) {
                int l = dfs(son, min(flow, w[i]));
                if (l) {
                    w[i] -= l, w[i ^ 1] += l;
                    flow -= l, sum += l;
                    if (!flow) break;
                }
            }
        }
        return sum;
    }
    int solve() {
        for (int i = 1; i <= m; i++) add(S, i), add(i + m, T);
        int ans = 0;
        while (bfs()) {
            for (int i = S; i <= T; i++) cur[i] = Begin[i];
            ans += dfs(S, inf);
        }
        return ans;
    }
}
struct node {
    int x, id;
    bool operator < (const node &t) const { return x < t.x; }
}A[maxn];
bool b[maxn][maxn];
bool check(int pos) {
    Dinic::init();
    for (int i = 1; i <= pos; i++)
        for (int j = 1; j <= pos; j++) {
            int x = A[i].id, y = A[j].id;
            if (i == j || !b[x][y]) continue;
            Dinic::add(x, y + m);
        }
    int res = Dinic::solve();
    return (pos - res) <= n;
}
int main() {
#ifdef xunzhen
    freopen("comp.in", "r", stdin);
    freopen("comp.out", "w", stdout);
#endif
    n = read() + 1, m = read();
    for (int i = 1; i <= m; i++) {
        b[i][i] = 1; A[i] = (node){read(), i};
        int k = read();
        for (int j = 1; j <= k; j++) b[i][read()] = 1;
    }
    for (int k = 1; k <= m; k++)
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= m; j++)
                b[i][j] |= b[i][k] & b[k][j];
    sort(A + 1, A + m + 1);
    int l = 1, r = m;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (check(mid)) l = mid + 1;
        else r = mid - 1;
    }
    if (l <= m) printf("%d\n", A[l].x);
    else puts("AK");
    return 0;
}第一次做最小链覆盖的题,感觉不是太难,过了样例就直接A了
原文:https://www.cnblogs.com/xunzhen/p/9733399.html