题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2414
题意:在网格上有一些小点,现在给出一个大炮,一次只能打一行(列),求最少多少次能清除全部小点。输出要打的行和列。
思路:
最小点覆盖=二分最大匹配。
二分最小点覆盖集。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int w,h,n,x,y;
int mpp[1010][1010],vis[1010],Y[1010],X[1010],d[1010];
int found(int x)
{
d[x]=true;
for(int i=1; i<=w; i++)
{
if(mpp[x][i]==true&&vis[i]==false)
{
vis[i]=true;
if(!Y[i]||found(Y[i]))
{
Y[i]=x;
X[x]=i;
return true;
}
}
}
return false;
}
int hun()
{
int ans=0;
for(int i=1; i<=h; i++)
{
memset(vis,0,sizeof(vis));
if(found(i))
{
ans++;
}
}
return ans;
}
int main()
{
while(~scanf("%d%d%d",&h,&w,&n),h||w||n)
{
memset(X,0,sizeof(X));
memset(Y,0,sizeof(Y));
memset(mpp,0,sizeof(mpp));
for(int i=1; i<=n; i++)
{
scanf("%d%d",&x,&y);
mpp[x][y]=true;
}
printf("%d",hun());
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
for(int i=1; i<=h; i++)
{
if(!X[i])
{
found(i);
}
}
for(int i=1; i<=h; i++)
{
if(d[i]==0)
printf(" r%d",i);
}
for(int i=1; i<=w; i++)
{
if(vis[i]==1)
printf(" c%d",i);
}
printf("\n");
}
}