Files
python/TangDou/AcWing/ErFenTu/379.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

2.4 KiB
Raw Blame History

##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;
}