1. 程式人生 > 其它 >【最小路徑可重點覆蓋】Vani和Cl2捉迷藏

【最小路徑可重點覆蓋】Vani和Cl2捉迷藏

題意

給出一張有向無環圖\(G=(V,E)\)\(|V|\leq 200,|E|\leq 30000\)
求出最多的\(k\)個點使得這\(k\)個點任意兩個之間都沒有路徑相連。

思路

是一個點的集合,這個集合中任意兩個元素\(u,v\),要麼\(u\)能走到\(v\),要麼\(v\)能走到\(u\)
反鏈是一個點的集合,這個集合中任意兩點誰也不能走到誰
最長反鏈是反鏈中最長的那個。

該題即求最長反鏈。

Dilworth定理:最長反鏈長度=最小鏈覆蓋數

故求出最小路徑可重點覆蓋即可。

程式碼

#include <cstdio>
#include <cstring>

const int V = 201, E = 30001;
int n, m, tot, ans;
int f[V][V];
int ver[E], next[E], head[V], line[V], v[V];

int find(int x) {
	for (int i = 1; i <= n; i++)
		if (f[x][i] && !v[i]) {
			v[i] = 1;
			if (!line[i] || find(line[i])) {
				line[i] = x;
				return 1;
			}
		}
	return 0;
}

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1, x, y; i <= m; i++)
		scanf("%d %d", &x, &y), f[x][y] = 1;
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				f[i][j] |= f[i][k] && f[k][j];
	for (int i = 1; i <= n; i++) {
		memset(v, 0, sizeof(v));
		ans += find(i);
	}
	printf("%d", n - ans);
}