POJ 3041-Asteroids-小行星二维快速打击:二分图最小顶点覆盖

原题链接
在这里插入图片描述
光束的攻击选择可以是横坐标从 x = 1 x=1 x=1 x = N x=N x=N和纵坐标从 y = 1 y=1 y=1 y = N y=N y=N, 一共 2 N 2N 2N种。显然,同样的选择没有必要执行多次,而攻击的顺序对结果没有影响,所以总的攻击方案共有 2 2 N 2^{2N} 22N。我们只要在这个解空间中,寻找能够摧毁所有小行星的最小的解就可以了。要破坏某个小行星,只能通过对应水平方向或竖直方向的光束的攻击。利用攻击方法只有两种这一点,我们可以将问题按如下方法转换为图。

把光束当作图的顶点,而把小行星当作连接对应光束的边。这样转换之后,光束的攻击方案即对应一个顶点集合 而要求攻击方案能够摧毁所有的小行星,也就是图中的每条边都至少有一个属于 S S S的端点。这样一来,问题就转为了求最小的满足上述要求的顶点集合 S S S
在这里插入图片描述
这正是最小顶点覆盖的问题。之前我们已经介绍过,最小顶点覆盖问题通常是NP困难的,不过在二分图中等于最大匹配,因而可以高效地求解。事实上,本题中所有顶点可以分成水平方向和竖直方向的攻击选择两类,而每颗小行星所对应的边都分别与一个水平方向和一个竖直方向的顶点相连,所以是二分图。因此,只要运用二分图最大匹配算法,问题就会迎刃而解了。二分图匹配

#include<iostream>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<iomanip>
using namespace std;

#define ll long long
#define vec vector<ll>
#define arr vector<vec>
#define Max 1005

ll n, m, V, used[Max], ans = 0, R[Max], edge[Max][Max];
//贝尔曼算法求二分图最大匹配
bool match(ll r) {
	for (ll i = 1; i <= n; i++) {
		if (edge[r][i] && !used[i]) {
			used[i] = 1; 
			if (!R[i] || match(R[i])) {
				R[i] = r; return true;
			}
		}
	}
	return false;
}

int main() {
	cin >> n >> m; V = 2 * n;
	for (ll i = 1; i <= m; i++) {
		ll a, b; cin >> a >> b;
		edge[a][b] = 1;
	}
	for (ll i = 1; i <= n; i++) {
		memset(used, 0, sizeof(used));
		if (match(i)) ans++;
	}
	cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值