这道题和hdu 1054同样是二分图匹配相关的问题。
二分图
最大匹配数=最小点覆盖数。
DAG 最小路径覆盖=顶点数-最大匹配数
最大独立集=顶点数-最大匹配数。
当一个图是无向图时,需要从每一个顶点进行最大匹配查找,所以无向图的最大匹配数是求出的最大匹配数/2;
或者可以理解为: 当图是无向图时, 左边的集合是包含了所有的顶点, 是有向图时,只包含了一部分顶点。
匈牙利算法:
vector<int> left_set;
vecto<int> adj[n];// n is the node num
// adj is a array or vector is the set of adj node of v;
bool dfs(int v){
for(int i=0;i<adj[v].size();i++){
if(!visited[adj[v][i]])
{
visited[adj[v][i]]=true;
if(match[adj[v][i]]==-1||dfs(match[adj[v][i]]){
match[adj[v][i]]=v;
return true;
}
}
}
}
int hungarian(){
int num=0;
for(int i=0;i<left_set.size();i++){ // 对于无向图 left_set 是整个集合
memset(visited,false,sizeof(visited));
if(dfs(left_set[i]) num++;
}
}
另外对于多组输入数据,记得每处理一组数据后,把一些变量重新设为初始状态,比如,清空vector
重置状态数组为初始状态等。
下面是代码:
#include <iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
#define MAX 100000
vector<int> stu[MAX];
int match[MAX];
bool visited[MAX];
int n;
bool dfs(int i){
for(int j=0;j<stu[i].size();j++){
int tmp=stu[i][j];
//not have visited
if(!visited[tmp]){
visited[tmp]=true;
if(match[tmp]==-1||dfs(match[tmp])){
match[tmp]=i;
return true;
}
}
}
return false;
}
int hungarian(){
memset(match,-1,sizeof(match));
int num=0;
for(int i=0;i<n;i++){
memset(visited,false,sizeof(visited));
if(dfs(i)) num++;
}
return num;
}
int main()
{
while(scanf("%d",&n)!=EOF){
int id,r; // id and the num
for(int i=0;i<n;i++) stu[i].clear();
for(int i=0;i<n;i++){
scanf("%d: (%d)",&id,&r);
for(int j=0;j<r;j++){
int tmp;
cin>>tmp;
stu[id].push_back(tmp);
}
}
int matchNum=hungarian()/2;
int result=0;
result=n-matchNum;
cout<<result<<endl;
}
return 0;
}