CH6803 导弹防御塔(二分图匹配-多重匹配)
链接: 6803 导弹防御塔
根据题意,二分最少的时间,然后连边看看能不能全部匹配。
每个炮塔能发射多发炮弹,所以将每个炮塔拆成多个炮弹,让怪和炮弹相连,对于第 i 个怪和第 j 个炮塔的第 k 个炮弹,打击所需的时间为\(dis(i, j) / v + k * t_1 + (k - 1) * t_2)\) (第 k 个炮弹发射出之前要等k个\(t_1\)和 k - 1 个\(t_2\))。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 55;
const int M = 2505;
const double e = 1e-9;
int n, m, t;
double t1, t2, v;
struct node {
double x, y;
} a[N], b[N], c[M];
int nextt[M * N], to[M * N], head[N], cnt = 0;
int match[M], tot = 0;
bool vis[M];
void add(int x, int y) {
nextt[++cnt] = head[x];
to[cnt] = y; head[x] = cnt;
}
double dist(int i, int j) {
double tmp1 = (a[i].x - b[j].x) * (a[i].x - b[j].x);
double tmp2 = (a[i].y - b[j].y) * (a[i].y - b[j].y);
double dist = sqrt(tmp1 + tmp2);
return dist;
}
void update(double p) {
cnt = 0;
memset(head, 0, sizeof(head));
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
c[(i - 1) * n + j].x = j;
c[(i - 1) * n + j].y = i * t1 + (i - 1) * t2;
}
}
for(int i = 1; i <= m; i++) {
for(int k = 1; k <= t; k++) {
if(dist(i, c[k].x) / v + c[k].y <= p) add(i, k);
}
}
}
bool dfs(int x) {
for(int i = head[x]; i; i = nextt[i]) {
int y = to[i];
if(vis[y]) continue;
vis[y] = true;
if(!match[y] or dfs(match[y])) {
match[y] = x; return true;
}
}
return false;
}
bool check(double p) {
update(p);
int ans = 0;
memset(match, 0, sizeof(match));
for(int i = 1; i <= m; i++) {
memset(vis, 0, sizeof(vis));
if(!dfs(i)) return false;
}
return true;
}
int main() {
// freopen("data.in", "r", stdin);
scanf("%d%d%lf%lf%lf", &n, &m, &t1, &t2, &v);
t1 /= 60.0; t = n * m;
for(int i = 1; i <= m; i++) {
scanf("%lf%lf", &a[i].x, &a[i].y);
}
for(int i = 1; i <= n; i++) {
scanf("%lf%lf", &b[i].x, &b[i].y);
}
double l = t1, r = 60000.0;
while(r - l > e) {
double mid = (l + r) / 2.0;
if(check(mid)) r = mid;
else l = mid;
}
printf("%.6lf", l);
return 0;
}