求最小覆盖集 , 并输出方案。
二分图的相关性质:
最小覆盖集 = 最大匹配数
最大独立集 = 节点数 - 最大匹配
即最大独立集和最小覆盖集互补。
要输出方案的话 。 从所有左边的未匹配点出发dfs()
则有: 最大独立集 = S + T'
最小覆盖集 = S' +T .
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1010 ;
struct O{
int n , m ;
vector<int>G[maxn];
bool S[maxn] , T[maxn];
int left[maxn] , right[maxn] ;
void init(int n , int m){
for(int i=0;i<=n;i++) G[i].clear();
this->n = n;
this->m = m;
}
bool dfs(int u){
S[u] = true;
for(vector<int>::iterator it = G[u].begin(); it!=G[u].end() ;it++){
if(T[*it]) continue;
T[*it] = true;
if(left[*it] == -1 || dfs(left[*it])) {
left[*it] = u;
right[u] = *it;
return true;
}
}
return false;
}
int max_match(){
int ans = 0;
memset(left , -1 ,sizeof(left)) ;
memset(right , -1 ,sizeof(right));
for(int i=0;i<n;i++) {
memset(S ,0 ,sizeof(S));
memset(T , 0 ,sizeof(T));
if(dfs(i)) ans++;
}
return ans;
}
// 从左边所有未盖点dfs ,
// 最小覆盖集: S'+T
// 最大独立集 S+T'
int solve(vector<int>&X , vector<int>&Y){
X.clear() , Y.clear();
int ans = max_match() ;
memset(S ,0 ,sizeof(S)) ;
memset(T , 0 ,sizeof(T));
for(int i=1;i<=n;i++) if(right[i] == -1) dfs(i);
for(int i=1;i<=n;i++) if(!S[i]) X.push_back(i);
for(int i=1;i<=m;i++) if(T[i]) Y.push_back(i);
return ans ;
}
}sol;
int main()
{
int n , m , k;
while(scanf("%d%d%d" ,&n ,&m, &k)==3 && n){
int x, y;
sol.init(n , m);
while(k--){
scanf("%d%d" ,&x , &y);
sol.G[x].push_back(y);
}
vector<int>X , Y ;
int ans = sol.solve(X , Y);
int xn = X.size() , yn = Y.size();
printf("%d" , ans);
for(int i=0; i<xn ;i++) printf(" r%d" , X[i]) ;
for(int i=0; i<yn ;i++) printf(" r%d" ,Y[i]) ;
printf("\n") ;
}
return 0;
}