AcWing 379 捉迷藏

\(AcWing\) \(379\) 捉迷藏

一、题目描述

\(Vani\) 和 \(cl2\) 在一片树林里捉迷藏。

这片树林里有 \(N\) 座房子,\(M\) 条有向道路,组成了一张 有向无环图(\(DAG\))。

树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。

如果从房子 \(A\) 沿着路走下去能够到达 \(B\),那么在 \(A\) 和 \(B\) 里的人是能够相互望见的。

现在 \(cl2\) 要在这 \(N\) 座房子里选择 \(K\) 座作为藏身点,同时 \(Vani\) 也专挑 \(cl2\) 作为藏身点的房子进去寻找,为了避免被 \(Vani\) 看见,\(cl2\) 要求这 \(K\) 个藏身点的任意两个之间都没有路径相连。

为了让 \(Vani\) 更难找到自己,\(cl2\) 想知道最多能选出多少个藏身点。

输入格式
输入数据的第一行是两个整数 \(N\) 和 \(M\)。

接下来 \(M\) 行,每行两个整数 \(x,y\),表示一条从 \(x\) 到 \(y\) 的有向道路。

输出格式
输出一个整数,表示最多能选取的藏身点个数。

数据范围
\(N≤200,M≤30000\)
输入样例:

7 5
1 2
3 2
2 4
4 5
4 6

输出样例:

3

二、解题思路

最小路径覆盖 与 最大独立点集

三、实现代码

#include <bits/stdc++.h>
using namespace std;
const int N = 210, M = 30010;
int n, m;
int g[N][N], st[N];
int match[N];

int dfs(int x) {
    for (int i = 1; i <= n; i++) {
        if (g[x][i] && !st[i]) {
            st[i] = 1;
            int t = match[i];
            if (t == -1 || dfs(t)) {
                match[i] = x;
                return 1;
            }
        }
    }
    return 0;
}

int main() {
    memset(match, -1, sizeof match);
    scanf("%d %d", &n, &m);

    while (m--) {
        int a, b;
        scanf("%d %d", &a, &b);
        g[a][b] = 1;
    }

    // floyd求传递闭包
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] |= g[i][k] & g[k][j];

    int res = 0;
    for (int i = 1; i <= n; i++) {
        memset(st, 0, sizeof st);
        if (dfs(i)) res++;
    }
    printf("%d\n", n - res);
    return 0;
}
posted @ 2022-04-05 16:41  糖豆爸爸  阅读(175)  评论(0)    收藏  举报
Live2D