题目大意
给一个有向无环图,n个点,m条边。让你派遣一些伞兵降落到某些点上并走完所有的点,所有伞兵的路径不能有重叠。即求最少边覆盖。
定理
最小边覆盖 = 点数 - 二分图最大匹配数
分析
因为每个伞兵的路径不能重叠,所以每个点的出度和入度最大为1.
题目化简为,选取一些边,使得所有点的出度和入度最大为1.
因为增加一条边就可以省去一个伞兵,所以答案 = 点数 - 选取边数
因为出度和入度只能是1 或者 0,可以对应到二分图里的匹配和未匹配。
所以把每个点的出度和入度分开,分成两个集合。就能在两个集合上做二分图匹配。匹配的边即图上选中的边。
AC代码
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 200;
const int inf = 1e9;
#define fast ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
int G[maxn][maxn];
int vis[maxn], match[maxn];
int n, m;
int find(int x){
for(int i = 1 ; i <= n ; i++){
if(G[x][i] && !vis[i]){
vis[i] = 1;
if(match[i] == 0 || find(match[i])){
match[i] = x;
return 1;
}
}
}
return 0;
}
int main(){
int T;
cin >> T;
while(T--){
cin >> n >> m;
memset(G, 0, sizeof G);
memset(match, 0, sizeof match);
int l, r;
for(int i = 1 ; i <= m ; i++){
cin >> l >> r;
G[l][r] = 1;
}
int ans = n;
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= n ; j++)vis[j] = 0;
ans -= find(i);
}
cout << ans << endl;
}
}