题目链接:http://poj.org/problem?id=3041
题目大意:
给你一个nxn的方阵,X代表一个敌人,可以在方阵内放置炸弹,炸弹可以炸掉所在在一行或者所在的一列,求最少需要多少个炸弹才能炸掉所有的敌人。
解题思路:
我们可以把行的坐标当成X集合,列坐标当成Y集合,那么每个敌人就是一条边。这样就构成了一个二分图。要求的是二分图最小点集覆盖。由定理可知,二分图最小点集覆盖等于最大匹配。所以,用匈牙利算法求出最大匹配即可。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define M 510 #define N 10010 int Head[M], Next[N], Key[N]; int match[M]; bool use[M]; int num; void add(int u, int v) { Key[num] = v; Next[num] = Head[u]; Head[u] = num++; } bool find(int u) { int temp; for(int i = Head[u]; i != -1; i = Next[i]) { temp = Key[i]; if(!use[temp]) { use[temp] = true; if(match[temp] == -1 || find(match[temp])) { match[temp] = u; return true; } } } return false; } int hungary(int n) { int sum = 0; for(int i = 1; i <= n; ++i) { memset(use, false, sizeof(use)); if(find(i)) sum++; } return sum; } int main() { int size, des; int x, y; while(scanf("%d%d", &size, &des) != EOF) { num = 0; memset(Head, -1, sizeof(Head)); memset(match, -1, sizeof(match)); for(int i = 1; i <= des; ++i) { scanf("%d%d", &x, &y); add(x, y); } printf("%d\n", hungary(size)); } return 0; }