很明显的二分图,只是这题需要输出最小覆盖的点
我们可以在求出最大匹配之后,以未覆盖的x点进行标记,沿着未覆盖->覆盖->未覆盖->覆盖...的路径标记,最后S中未标记的和T中标记的点构成最小点覆盖集。
// File Name: 11419.cpp // Author: zlbing // Created Time: 2013/3/1 14:20:03 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define MAXN 1050 int Left[MAXN]; int w[MAXN][MAXN]; bool S[MAXN],T[MAXN]; int N,M; bool match(int i) { S[i]=true; for(int j=1;j<=M;j++)if(w[i][j]&&!T[j]) { T[j]=true; if(Left[j]==0||match(Left[j])) { Left[j]=i; return true; } } return false; } void dfs(int i) { S[i]=true; for(int j=1;j<=M;j++)if(w[i][j]&&!T[j]) { T[j]=true; dfs(Left[j]); } } int main(){ int t; while(~scanf("%d%d%d",&N,&M,&t)) { if(N==0&&M==0&&t==0)break; int a,b; CL(w,0); for(int i=0;i<t;i++) { scanf("%d%d",&a,&b); w[a][b]=1; } CL(Left,0); int sum=0; for(int i=1;i<=N;i++) { CL(S,0); CL(T,0); if(match(i))sum++; } bool c[MAXN]; CL(c,0); for(int i=1;i<=M;i++)c[Left[i]]=1; CL(S,0);CL(T,0); for(int i=1;i<=N;i++) if(!c[i])dfs(i); printf("%d",sum); for(int i=1;i<=N;i++) if(!S[i])printf(" r%d",i); for(int i=1;i<=M;i++) if(T[i])printf(" c%d",i); printf("\n"); } return 0; }