Radar
Each of the last M lines consists of the coordinate of a radar station.
All coordinates are separated by one space.
Technical Specification
1. 1 ≤ T ≤ 20
2. 1 ≤ N, M ≤ 50
3. 1 ≤ K ≤ M
4. 0 ≤ X, Y ≤ 1000
1 3 3 2 3 4 3 1 5 4 1 1 2 2 3 3
2.236068
这道题的大意就是说有m个监控范围一样的雷达, 监控范围为圆形. 现在给出n个城市的二维坐标, 问能否用<=K个雷达覆盖所有城市, 若果能请求出能覆盖的最小的半径.
又是覆盖问题... 那么要在满足限制的条件下得出最小解, 那一般都是二分答案... 考虑怎么check. 如果二分的是半径, 那么每个雷达能覆盖哪些城市就能够确定... 再看一下数据范围... 搜索可搞. 又要求完全覆盖, 自然想到跳舞链. 雷达为行, 城市为列, 这样就转化模型了. 然后就是裸的重复覆盖.(没要求一个城市只能被一个雷达覆盖).
对于重复覆盖问题, 与精确覆盖的区别就在于删的方式. 精确覆盖删行, 重复覆盖删列. 比如说选择了c列, 那么就把c列删去, 然后对于选择的某行i, i覆盖了哪些列就把哪些列删去. 之所以不能删行就是因为可以重复覆盖. 但是这样删的力度不大, 就会导致了图会很慢才能变得稀疏. 所以要像A*那样写一个最乐观的估价函数. 如果这个函数返回的值加上当前已经删去的行>K, 那么显然不必要再往更深里搜索了.
#include<bits/stdc++.h>
using namespace std;
const int maxm = 55;
const int maxn = 3e3;
const double eps = 1e-8;
bool vis[maxm];
int n, m, siz, N, M, K, T;
int s[maxm], h[maxm];
int le[maxn], ri[maxn], up[maxn], dw[maxn], col[maxn];
inline void init(const int &r, const int &c) {
n = r, m = c, siz = m;
for (int i = 0; i <= m; ++ i) {
s[i] = 0;
le[i] = i - 1;
ri[i] = i + 1;
up[i] = dw[i] = i;
}
ri[m] = 0, le[0] = m;
for (int i = 1; i <= n; ++ i) h[i] = -1;
}
inline void link(const int &r, const int &c) {
s[col[++ siz] = c] ++;
dw[siz] = dw[c], up[dw[c]] = siz;
dw[c] = siz, up[siz] = c;
if (h[r] < 0) h[r] = le[siz] = ri[siz] = siz;
else {
ri[siz] = ri[h[r]], le[ri[h[r]]] = siz;
ri[h[r]] = siz, le[siz] = h[r];
}
}
inline void resume(const int &c) {
for (int i = dw[c]; i != c; i = dw[i])
le[ri[i]] = ri[le[i]] = i;
}
inline void remove(const int &c) {
for (int i = dw[c]; i != c; i = dw[i])
le[ri[i]] = le[i], ri[le[i]] = ri[i];
}
inline int Astar() {
int ret = 0;
for (int c = ri[0]; c; c = ri[c]) vis[c] = true;
for (int c = ri[0]; c; c = ri[c])
if (vis[c]) {
ret ++;
vis[c] = false;
for (int i = dw[c]; i != c; i = dw[i])
for (int j = ri[i]; j != i; j = ri[j])
vis[col[j]] = false;
}
return ret;
}
bool Dance(int d) {
if (!ri[0]) return d <= K;
if (d + Astar() > K) return false;
int c = ri[0];
for (int i = ri[0]; i; i = ri[i])
if (s[i] < s[c]) c = i;
for (int i = dw[c]; i != c; i = dw[i]) {
remove(i);
for (int j = ri[i]; j != i; j = ri[j]) remove(j);
if (Dance(d + 1)) return true;
for (int j = le[i]; j != i; j = le[j]) resume(j);
resume(i);
}
return false;
}
struct Point {
int x, y;
inline friend double operator * (const Point &r, const Point &s) {
return sqrt((double)(r.x - s.x) * (r.x - s.x) + (double)(r.y - s.y) * (r.y - s.y));
}
}a[maxm], b[maxm];
int main() {
scanf("%d", &T);
while (T --) {
scanf("%d%d%d", &N, &M, &K);
for (int i = 0; i < N; ++ i)
scanf("%d%d", &a[i].x, &a[i].y);
for (int i = 0; i < M; ++ i)
scanf("%d%d", &b[i].x, &b[i].y);
double lf = 0, rg = 1e8;
while (rg - lf >= eps) {
double mid = (lf + rg) / 2;
init(M, N);
for (int i = 0; i < M; ++ i)
for (int j = 0; j < N; ++ j)
if (b[i] * a[j] < mid - eps)
link(i + 1, j + 1);
if(Dance(0)) rg = mid - eps;
else lf = mid + eps;
}
printf("%.6f\n", lf);
}
}

本文介绍了一种使用二分查找和跳舞链算法解决雷达站点最优覆盖问题的方法,旨在找到最少数量的雷达站以覆盖所有目标城市。
433

被折叠的 条评论
为什么被折叠?



