CH6803 导弹防御塔

题目链接  https://www.acwing.com/problem/content/376/

题目描述

Freda的城堡遭受了 M 个入侵者的攻击!

Freda控制着 N 座导弹防御塔,每座塔都有足够数量的导弹,但是每次只能发射一枚。

在发射导弹时,导弹需要 T1 秒才能从防御塔中射出,而在发射导弹后,发射这枚导弹的防御塔需要 T2 分钟来冷却。

所有导弹都有相同的匀速飞行速度 V,并且会沿着距离最短的路径去打击目标。

计算防御塔到目标的距离Distance时,你只需要计算水平距离,而忽略导弹飞行的高度。

导弹在空中飞行的时间就是 (Distance/V) 分钟,导弹到达目标后可以立即将它击毁。

现在,给出 N 座导弹防御塔的坐标,M 个入侵者的坐标,T1,T2 和 V。因为Freda的小伙伴Rainbow就要来拜访城堡了,你需要求出至少多少分钟才能击退所有的入侵者。

输入格式

第一行五个正整数N,M,T1,T2,V。

接下来 M 行每行两个整数,代表入侵者的坐标。

接下来 N 行每行两个整数,代表防御塔的坐标。

输出格式

输出一个实数,表示最少需要多少分钟才能击中所有的入侵者,四舍五入保留六位小数。

数据范围1≤N,M≤50,坐标绝对值不超过10000,T1,T2,V不超过2000。

防御塔与入侵者可以看作二分图的两部分,显然,防御塔可以被匹配多次,可以明显看出这是一个多重匹配问题。

本文介绍的解法是,拆点法。

既然防御塔可以匹配多次,就将多次的匹配拆开,设可以匹配n次,就拆分成n个点,相当于每个点匹配一次。本题要求的是最短时间,如果一个显然可以用二分的思想,如果小的时间点满足条件,显然大的也满足。二分时间,什么样的时间满足条件呢?就是在该时间限制下,建图,每个防御塔的炮弹从发出到命中(包含冷却时间,第一个炮弹冷却可看作0)的时间不能超过所限制的时间,如果满足条件,则建一条双向边。在建好的图中跑最大匹配,如果最大匹配数等于入侵者的数量M,说明每个入侵者都有一个炮弹于其对应,则说明满足条件。

注意:本题坑点诸多!!!首先,输入的是N,MT1,T2,V,但是下面输入的时候先输入M个入侵者,再输入N个炮台,其次,T1的单位是秒!!!!!!需要先将其化为分钟再计算!lyd大佬真费心了!!!

#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof a)
#define eps 1e-8
using namespace std;
const int N = 60;
const int M = 4e5;
int head[M], nex[M], to[M];
bool vis[M];
int match[M];
int cnt;
double times[N];
int n, m, T1, T2, V;
double t1, t2, v;
struct p{
	double x, y;
} in[N], out[N];
inline void add(int a, int b){
	++cnt;
	to[cnt] = b;
	nex[cnt] = head[a];
	head[a] = cnt;
}
inline double dist(p& a, p& b){
	double dx = a.x - b.x;
	double dy = a.y - b.y;
	return sqrt(dx * dx + dy * dy);
}
void build(double ti){
	mem(head, -1);
	mem(nex, -1);
	cnt = 0;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			for (int k = 1; k <= m; k++){
				if (times[j] + dist(out[i], in[k]) / v <= ti){
					add(k, m + (i - 1) * 50 + j);
					add(m + (i - 1) * 50 + j, k);
				}
			}
		}
	}
}
bool dfs(int x){
	for (int i = head[x]; i != -1; i = nex[i]){
		int y = to[i];
		if (vis[y])continue;
		vis[y] = 1;
		if (match[y] == -1 || dfs(match[y])){
			match[y] = x;
			return 1;
		}
	}
	return 0;
}
bool check(double ti){
	build(ti);
	mem(match, -1);
	int ans = 0;
	for (int i = 1; i <= m; i++){
		mem(vis, 0);
		if (dfs(i))ans++;
	}
	return ans == m;
}
int main()
{
//	freopen("in.in", "r", stdin);
	scanf("%d %d %d %d %d", &n, &m, &T1, &T2, &V);
	t1 = T1;
	t1 /= 60.0;
	t2 = T2;
	v = V;
	for (int i = 1; i <= 55; i++){
		times[i] = t1 * i + t2 * (i - 1);
	}
	for (int i = 1; i <= m; i++){
		int x, y;
		scanf("%d %d", &x, &y);
		in[i].x = x * 1.0;
		in[i].y = y * 1.0;
	}
	for (int i = 1; i <= n; i++){
		int x, y;
		scanf("%d %d", &x, &y);
		out[i].x = x * 1.0;
		out[i].y = y * 1.0;
	}
	double l, r;
	l = 0;
	r = 100000;
	double res = -1;
	while (r - l > eps){
		double mid = (l + r) / 2;
		if (check(mid)){
			res = mid;
			r = mid;
		}
		else l = mid;
	}
	printf("%.6lf\n", res);
	return 0;
}
发布了204 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43701790/article/details/104584008