对应POJ题目:点击打开链接
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 15911 | Accepted: 8662 |
Description
Input
Output
Sample Input
3 4 1 1 1 3 2 2 3 2
Sample Output
2
Hint
Source
题意:在一个N*N的图里,散布着一些小行星,小明有一支很牛逼的枪,他一枪可以把某一行或某一列的小行星化为尘埃,问小明至少需要多少枪才能把所以的小行星消灭掉。
思路:把行放在X集合,列放在Y集合,那在某坐标的小行星就表示从X集合的某行连一条线到Y集合中的某列,一枪打在X集合里的某行,就表示该行所连的边也会被打到,Y集合的列同理。那问题就变为求二分图的最小点覆盖数了。。。
最小点覆盖数 = = 最大匹配数
假设最大匹配数为M,最小覆盖点数为N;
则每条边最少需要1个点关联,即N >= M;
又N <= M;因为只需要每个点分别关联每条匹配边,那其他边肯定会被某些点关联到,假设还存在某条边没有被关联到,就说明还没有达到最大匹配。
所以N == M;
#include<cstdio> #include<cstdlib> #include<cmath> #include<map> #include<queue> #include<stack> #include<vector> #include<algorithm> #include<cstring> #include<string> #include<iostream> #define ms(x,y) memset(x,y,sizeof(x)) const int MAXN=500+10; const int INF=1<<30; using namespace std; bool net[MAXN][MAXN]; bool vis[MAXN]; int link[MAXN]; int n,m; bool dfs(int u) { for(int v=1; v<=n; v++){ if(!vis[v] && net[u][v]){ vis[v] = 1; if(link[v] == -1 || dfs(link[v])){ link[v] = u; return 1; } } } return 0; } int MaxMatch() { int num = 0; ms(link,-1); for(int u=1; u<=n; u++){ ms(vis,0); if(dfs(u)) num++; } return num; } int main() { //freopen("in.txt","r",stdin); scanf("%d%d", &n,&m); for(int i=1; i<=m; i++){ int u,v; scanf("%d%d", &u,&v); net[u][v] = 1; } int ans = MaxMatch(); printf("%d\n", ans); return 0; }