题目链接:

​http://poj.org/problem?id=3041​


题目大意:

有一个N*N的矩阵,有些格子上有障碍物(坐标为(x,y) ),在消除这些障碍物的时候,可以一次性消除

该障碍物同一行所有的障碍物,或是一次性消除该障碍物同一列所有的障碍物。只能选择清理该行或是

清理该列。问:最小进行多少次消除,就可以清理所有的障碍物。


思路:

可以将每一行当做一个点,这样总共有N个点,作为二分图的一边。将每一列当做一个点,这样又有N

个点,作为二分图的另一边。将有障碍物的行点和列点连接起来,每次只能选择行或是列,需要清除所

有的障碍物。所以不能存在一条边两边的点都没有被选中的情况。这样问题就转变为选择最少的一些点

(行点或是列点),使得从这些点与所有的边相连,也就是二分图最小点覆盖问题。


AC代码:


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

const int MAXN = 550;

bool Map[MAXN][MAXN],Mask[MAXN];

int NX,NY;
int cx[MAXN],cy[MAXN];

int FindPath(int u)
{
for(int i = 1; i <= NY; ++i)
{
if(Map[u][i] && !Mask[i])
{
Mask[i] = 1;
if(cy[i] == -1 || FindPath(cy[i]))
{
cy[i] = u;
cx[u] = i;
return 1;
}
}
}
return 0;
}

int MaxMatch()
{
for(int i = 1; i <= NX; ++i)
cx[i] = -1;
for(int i = 1; i <= NY; ++i)
cy[i] = -1;

int res = 0;
for(int i = 1; i <= NX; ++i)
{
if(cx[i] == -1)
{
for(int j = 1; j <= NY; ++j)
Mask[j] = 0;
res += FindPath(i);
}
}
return res;
}

int main()
{
int N,M,u,v;
while(~scanf("%d%d",&N,&M))
{
NX = NY = N;
memset(Map,0,sizeof(Map));
for(int i = 1; i <= M; ++i)
{
scanf("%d%d",&u,&v);
Map[u][v] = 1;
}
printf("%d\n",MaxMatch());
}

return 0;
}