题目链接:
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; }