HDU-2255 Rain on your Parade (二分图-Hopcroft-Carp)

题目链接

题意:给出t组数据,每组数据有一个时间T,n个人的坐标(x,y)即速度s,又给出m把雨伞的坐标(x,y),求在T秒时最多有多少人拿到雨伞(不淋雨).

题解:由于数据很大,故不能用匈牙利,套Hopcroft-Carp模板即可,时间复杂度为O(sqrt(V)*E).

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 3300;
struct Hopcroft_Karp {
	int n1, n2, ans;  //n1为左边的点数,n2为右边的点数,ans为最大匹配数
	vector<int>g[maxn];  //g[i]表示与左边i点相匹配的点
	int mx[maxn], my[maxn];
	//mx[i]表示最大匹配中与左边的i相连的点,my[i]表示最大匹配中与右边的点相连的点
	int dx[maxn], dy[maxn];
	bool vis[maxn];
	queue<int>q;
	bool find(int u) {
		for (int i = 0; i < g[u].size(); i++) {
			if (!vis[g[u][i]] && dy[g[u][i]] == dx[u] + 1) {
				vis[g[u][i]] = true;
				if (!my[g[u][i]] || find(my[g[u][i]])) {
					mx[u] = g[u][i];
					my[g[u][i]] = u;
					return true;
				}
			}
		}
		return false;
	}
	void matching() {//跑一遍即可得到答案ans的结果
		memset(mx, 0, sizeof(mx));
		memset(my, 0, sizeof(my));
		ans = 0;
		while (1) {
			bool flag = false;
			while (!q.empty())q.pop();
			memset(dx, 0, sizeof(dx));
			memset(dy, 0, sizeof(dy));
			for (int i = 1; i <= n1; i++)
				if (!mx[i])q.push(i);
			while (!q.empty()) {
				int u = q.front(); q.pop();
				for (int i = 0; i < g[u].size(); i++) {
					if (!dy[g[u][i]]) {
						dy[g[u][i]] = dx[u] + 1;
						if (my[g[u][i]]) {
							dx[my[g[u][i]]] = dy[g[u][i]] + 1;
							q.push(my[g[u][i]]);
						}
						else
							flag = true;
					}
				}
			}
			if (!flag)break;
			memset(vis, 0, sizeof(vis));
			for (int i = 1; i <= n1; i++)
				if (!mx[i] && find(i))ans++;
		}
	}
	void init(int nn1, int nn2) {
		n1 = nn1; n2 = nn2;
		for (int i = 1; i <= n1; i++)
			g[i].clear();
	}
}h;
struct node {
	double x, y, s;
}a[maxn], b[maxn];
int main() {
	int t;
	double T;
	scanf("%d", &t);
	for (int cas = 1; cas <= t; cas++) {
		scanf("%lf", &T);
		scanf("%d", &h.n1);
		for (int i = 1; i <= h.n1; i++)
			scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].s);
		scanf("%d", &h.n2);
		for (int i = 1; i <= h.n2; i++)
			scanf("%lf%lf", &b[i].x, &b[i].y);
		h.init(h.n1, h.n2);
		for (int i = 1; i <= h.n1; i++)
			for (int j = 1; j <= h.n2; j++) {
				if (a[i].s*T >= sqrt((a[i].x - b[j].x)*(a[i].x - b[j].x) + (a[i].y - b[j].y)*(a[i].y - b[j].y)))
					h.g[i].push_back(j);
			}
		h.matching();
		printf("Scenario #%d:\n%d\n\n", cas, h.ans);
	}   return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值