給定一個有向無環圖(DAG),代表城鎮的單向街道和十字路口。傘兵可從任意路口著陸,並沿街道方向移動。每個路口只能被一名傘兵訪問。求訪問所有路口所需的最少傘兵數。
在 DAG 中,最小路徑覆蓋 = 頂點數 - 最大匹配數。將原圖每個頂點拆分為左右兩部分(U 集合和 V 集合),原有向邊 u→v 轉化為無向邊 u(U)-v(V)。在這個二分圖中求最大匹配,匹配邊代表路徑中的連接關係。未被匹配的左側頂點即為路徑起點,其數量即為最小路徑覆蓋數。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <math.h>
#define init(a) memset(a, 0, sizeof(a))
#define PI acos(-1.0)
using namespace std;
const int maxn = 310;
int ma[maxn][maxn];
int line[maxn];
bool vis[maxn];
int n, m;
int DFS(int u) {
for (int v = 1; v <= n; v++) {
if (!vis[v] && ma[u][v] == 1) {
vis[v] = true;
if (line[v] == -1 || DFS(line[v])) {
line[v] = u;
return 1;
}
}
}
return 0;
}
int K_M() {
int ans = 0;
memset(line, -1, sizeof(line));
for (int i = 1; i <= n; i++) {
init(vis);
ans += DFS(i);
}
return ans;
}
int main() {
int x, y, t;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
init(ma);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
ma[x][y] = 1;
}
int ans = K_M();
printf("%d\n", n - ans);
}
return 0;
}
Sample Input: 2 4 3 3 4 1 3 2 3 3 3 1 3 1 2 2 3 Sample Output: 2 1
第一個案例:4個頂點,3條邊 3→4, 1→3, 2→3。最大匹配為 2(如 1-3, 2-4 或 1-3, 3-4),答案 4-2=2。
第二個案例:3個頂點,邊 1→3, 1→2, 2→3。最大匹配 2(1-2, 2-3),答案 3-2=1。