题解: https://xiaoxiaoh.blog.csdn.net/article/details/104463150
一、内容
Vani和cl2在一片树林里捉迷藏。
这片树林里有N座房子,M条有向道路,组成了一张有向无环图。
树林里的树非常茂密,足以遮挡视线,但是沿着道路望去,却是视野开阔。
如果从房子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
二、思路
- 每条路径上的任意点都可以相互看到。那么我们可以求出这个图的最小路径重复点覆盖的条数cnt。 每条路径上我们至少可以选出一个点。 故藏身点的数量就等于 最小路径重复点覆盖的条数。
三、代码
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 205;
int n, m, u, v, g[N][N], mat[N];
bool vis[N];
bool dfs(int u) {
for (int v = 1; v <= n; v++) {
if (!g[u][v] || vis[v]) continue; vis[v] = true;
if (!mat[v] || dfs(mat[v])) {
mat[v] = u; return true;
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v); g[u][v];
}
//求传递闭包
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 ans = n;
//求出最大匹配
for (int i = 1; i <= n; i++) {
memset(vis, false, sizeof(vis));
ans -= dfs(i);
}
printf("%d\n", ans);
return 0;
}