AcWing379 捉迷藏(最小路径重复点覆盖)

本题是在DAG上求取最多的两两不相连的点

我们知道的是,所有某条路径上的点都是能看的见的

因此只有求出最小路径重复点覆盖,这样每条路径的起点就是不会被别的点走到,否则这条路径没有意义。

经过传递闭包后变成最小路径覆盖,而这个已经证明为总点数减去二分图的最大匹配(这个是特殊的,两方分别为出度和入度)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 210, M = 30010;

int n, m;
bool d[N][N], st[N];
int match[N];

bool find(int x)
{
    for (int i = 1; i <= n; i ++ )
        if (d[x][i] && !st[i])
        {
            st[i] = true;
            int t = match[i];
            if (t == 0 || find(t))
            {
                match[i] = x;
                return true;
            }
        }

    return false;
}

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

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

    int res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        memset(st, 0, sizeof st);
        if (find(i)) res ++ ;
    }

    printf("%d\n", n - res);

    return 0;
}
View Code

 

posted @ 2020-07-01 11:08  朝暮不思  阅读(165)  评论(0编辑  收藏  举报