题目链接:
[POJ 3041]Asteroids[二分图匹配]
题意分析:
Bessie要把阻挡她的小行星都炸掉,一次可以炸一排或一列,不过由于这种炮弹很值钱,所以她需要你计算最少需要用多少炮弹可以打掉所有行星。
解题思路:
把行星所在的x轴坐标看作图中的一个点,y轴坐标看作一个点,同一行星的x、y点间连一条直线,原问题就转换成了选出最少的点,让所有边都与其相连,也就是最小点覆盖(因为当这个点被射击了,对应的整个行或者列就会被射击到,相应的,其所连的边(边就是障碍物)都将消失)。最小点覆盖数 = 最大匹配数。具体证明参见这篇博文:点击打开链接 。然后求最大匹配数,用匈牙利算法就ok了。
个人感受:
第一次写二分图匹配~关于匈牙利算法,这里也有篇对于过程解释的很生动的文章:二分图匹配 - - 匈牙利算法
具体代码如下:#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f, MAXN = 5e2 + 111;
int n, k;
bool vis[MAXN], line[MAXN][MAXN];
int match[MAXN];
bool fin(int x)
{
for (int i = 1; i <= n; ++i)
{
if (line[x][i] && !vis[i])
{
vis[i] = 1;
if (!match[i] || fin(match[i]))
{
match[i] = x;
return 1;
}
}
}
return 0;
}
int main()
{
while (cin >> n >> k)
{
memset(line, 0, sizeof line);
memset(match, 0, sizeof match);
int x, y;
for (int i = 0; i < k; ++i)
{
cin >> x >> y;
line[x][y] = 1;
}
int ans = 0;
for (int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
if (fin(i)) ++ans;
}
cout << ans << '\n';
}
return 0;
}