Consider a town where all the streets are one-way and each street leads from one intersection to another. It is also known that starting from an intersection and walking through town’s streets you can never reach the same intersection i.e. the town’s streets form no cycles.
With these assumptions your task is to write a program that finds the minimum number of paratroopers that can descend on the town and visit all the intersections of this town in such a way that more than one paratrooper visits no intersection. Each paratrooper lands at an intersection and can visit other intersections following the town streets. There are no restrictions about the starting intersection for each paratrooper.
Input
Your program should read sets of data. The first line of the input file contains the number of the data sets. Each data set specifies the structure of a town and has the format:
no_of_intersections
no_of_streets
S1 E1
S2 E2
......
Sno_of_streets Eno_of_streets
The first line of each data set contains a positive integer no_of_intersections (greater than 0 and less or equal to 120), which is the number of intersections in the town. The second line contains a positive integer no_of_streets, which is the number of streets in the town. The next no_of_streets lines, one for each street in the town, are randomly ordered and represent the town’s streets. The line corresponding to street k (k <= no_of_streets) consists of two positive integers, separated by one blank: Sk (1 <= Sk <= no_of_intersections) - the number of the intersection that is the start of the street, and Ek (1 <= Ek <= no_of_intersections) - the number of the intersection that is the end of the street. Intersections are represented by integers from 1 to no_of_intersections.
There are no blank lines between consecutive sets of data. Input data are correct.
Output
The result of the program is on standard output. For each input data set the program prints on a single line, starting from the beginning of the line, one integer: the minimum number of paratroopers required to visit all the intersections in the town.
Sample Input
2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3
Sample Output
2
1
给出一个有向图,在一些节点上放小人,小人可以沿着边移动,求最少放几个小人可以把图中的节点都走一遍,且每个节点都只能走一次。
实际上,这个题的模型是有向图最小路径覆盖,等于 节点数 - 有向图对应的二分图的最大匹配。
首先说明有向图对应二分图的建立。将图中的每个节点拆分为 入点 和 出点,并将入点划为一个集合,出点划为另一个集合,这样就得到了两个互不相交的子集。
得到这个二分图之后,再来说说明这个图的最小路径覆盖为什么会等于 节点数 - 最大匹配数。
首先先假设这样一种情况,就是有一个节点为 n 的有向图,但是没有任何边,那么这个图最小路径覆盖就是 n 。之后再向这个图中加边,每加入一条边,便会取消两个点的独立性。如果这条边连个的两个点中,有一个点没有匹配的话,最小路径覆盖就会-1;如果两个点都匹配的话,就去找一条增广路,如果能找到,最小路径覆盖-1;不能找到最小路径覆盖不变。
注意,这里的最小路径覆盖是路径不相交的那种,如果路径可以相交则需要传递闭包计算节点连通性,这里不进行讨论。
由于数据量不大,这里用的是最直观的方法,将每个节点拆分后重新编号,出点继承原节点的编号,入点则在原节点编号的基础上 +125 。之后在计算最大匹配并结合关系是可以得出答案了。
#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>
#define MAXN 255
#define STAR 125
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
int match[MAXN];
bool used[MAXN];
vector<int> adj[MAXN];
bool dfs(int v);
int main(){
ios::sync_with_stdio(false);
int k;
cin>>k;
while(k--){
int n,len;
cin>>n>>len;
rep(i,0,len){
int commonA,commonB;
cin>>commonA>>commonB;
commonB+=STAR;
adj[commonA].Push(commonB);
adj[commonB].Push(commonA);
}
int ans=0;
memset(match,-1,sizeof(match));
rep(i,1,n+1){
if(match[i]<0){
memset(used,false,sizeof(used));
if(dfs(i))
ans++;
}
}
cout<<n-ans<<endl;
rep(i,0,MAXN)
adj[i].clear();
}
re 0;
}
bool dfs(int v){
used[v]=true;
rep(i,0,adj[v].size()){
int u=adj[v][i],matched=match[u];
if(matched<0 || !used[matched] && dfs(matched)){
match[u]=v;
match[v]=u;
return true;
}
}
return false;
}