The world is in great danger!! Mental’s forces have returned to
Earth to eradicate humankind. Our last hope to stop this great
evil is Sam “Serious” Stone. Equipped with various powerful
weapons, Serious Sam starts his mission to destroy the forces of
evil.
After fighting two days and three nights, Sam is now in front of
the temple KOPTOS where Mental’s general Ugh Zan III is waiting
for him. But this time, he has a serious problem. He is in shortage
of ammo and a lot of enemies crawling inside the temple waiting
for him. After rounding the temple Sam finds that the temple is
in rectangle shape and he has the locations of all enemies in the
temple.
All of a sudden he realizes that he can kill the enemies without entering the temple using the great
cannon ball which spits out a gigantic ball bigger than him killing anything it runs into and keeps on
rolling until it finally explodes. But the cannonball can only shoot horizontally or vertically and all the
enemies along the path of that cannon ball will be killed.
Now he wants to save as many cannon balls as possible for fighting with Mental. So, he wants to
know the minimum number of cannon balls and the positions from which he can shoot the cannonballs
to eliminate all enemies from outside that temple.
题目大意:
大小为R*C的网格图中存在一些点需要被打掉,每次可以选择打掉任意一行或任意一列,求最小的步数将所有的点都打掉,并输出方案
解题报告:
这题是一个简单的二分图最小点覆盖问题,显然如果每一条边对应一个网格图中的一个点的话,那么答案就是用最小的点去覆盖所有的边
考虑输出方案:
设左右两图分别为X,Y 我们选择X中未匹配的点去遍历他的出边,显然这样做答案就是X集合中未标记的点,Y集合中标记了的点,至于为什么Y中标记的点就是答案:因为假设X集合中a未被匹配,那么它所对应的出边就没有被覆盖,所以它的另外一边必然存在于最大匹配中
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=2005,M=1000005;
int head[N],to[M<<1],nxt[M<<1],n,m,k,bel[N],num=0;bool vis[N],v[N];
void link(int x,int y){
nxt[++num]=head[x];to[num]=y;head[x]=num;
}
int gi(){
int str=0;char ch=getchar();
while(ch>'9' || ch<'0')ch=getchar();
while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
return str;
}
bool dfs(int x){
int u;v[x]=true;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(vis[u])continue;
vis[u]=true;
if(!bel[u] || dfs(bel[u])){
bel[u]=x;bel[x]=u;
return true;
}
}
return false;
}
void Clear(){
memset(head,0,sizeof(head));num=0;
memset(bel,0,sizeof(bel));
}
void work()
{
Clear();
int x,y;
for(int i=1;i<=k;i++){
x=gi();y=gi();
link(x,y+n);link(y+n,x);
}
int ans=0;
for(int i=1;i<=n+m;i++){
if(!bel[i]){
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
}
printf("%d",ans);
memset(vis,0,sizeof(vis));
memset(v,0,sizeof(v));
for(int i=1;i<=n;i++)
if(!bel[i])dfs(i);
for(int i=1;i<=n;i++)
if(!v[i])printf(" r%d",i);
for(int i=1;i<=n;i++){
if(vis[i+n])printf(" c%d",i);
}
puts("");
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k)){
if(n+m+k==0)break;
work();
}
return 0;
}