题意: 你现在有n+m 个大炮, 现在在一个n*m的网格中有 c 个敌人 每一个大炮一发子弹可以干掉一行的敌人 或者一列的敌人
问你最少需要几发炮弹。 将大炮看成点 分为行点 和列点 ,每个敌人看成是边 那么就可以抽象成 用最少的点去覆盖 所有的边
二分图的最大匹配等于最小点覆盖。 但是这里要输出 最小点覆盖集 。。 方法是从 行点 所有没有被覆盖的点 出发扩展 匈牙利树。匈牙利树其实是匹配边和为匹配边的交替。 这样跑出来之后 行点对应的没有访问过的点和 列点访问过得点就是最小点覆盖集。
#include<bits/stdc++.h>
using namespace std;
const int N =1005;
int boy[N],girl[N];
vector< int >ve[N]; // 单向建边
int vis1[N];
int vis2[N];
int n,m,c;
int dfs(int x)
{
vis1[x]=1;
for(int i=0;i<ve[x].size();i++)
{
int v=ve[x][i];
if(!vis2[v]){
vis2[v]=1;
if(dfs(girl[v])||girl[v]==-1)
{
girl[v]=x;
boy[x]=v;
return 1;
}
}
}
return 0;
}
void xiongyali()
{
memset(boy,-1,sizeof(boy));
memset(girl,-1,sizeof(girl));
int cnt=0;
for(int i=1;i<=n;i++)
{
memset(vis2,0,sizeof(vis2));
if(dfs(i)) cnt++;
}
cout<<cnt;
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
for(int i=1;i<=n;i++)
{
if(boy[i]==-1){
dfs(i);
}
}
for(int i=1;i<=n;i++){
if(vis1[i]==0){
printf(" r%d",i);
}
}
for(int i=1;i<=m;i++){
if(vis2[i]){
printf(" c%d",i);
}
}
return ;
}
int main()
{
int u,v;
while(cin>>n>>m>>c)
{
for(int i=1;i<=n;i++) ve[i].clear();
if(n==0&&m==0&&c==0) break;
while(c--)
{
scanf("%d %d",&u,&v);
ve[u].push_back(v);
}
xiongyali();
printf("\n");
}
return 0;
}