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  糖豆爸爸  阅读(98)  评论(0编辑  收藏  举报
Live2D