本题是在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 - res); return 0; }