题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3156
题意:
给 n(1<=n<=16) 个点,点的坐标为 x,y(0<=x,y<=10) ,且x, y是实数,给m个维修点,坐标不限,求一个最小距离,使得n个点到m个维修点的距离至少有一个小于等于这个最小距离
思路:
自己不会,看的是这一篇题解:http://www.cnblogs.com/183zyz/archive/2011/08/09/2132767.html,明白了思路自己想了想,的确数据范围有点小,是应该用暴力的方法来求解
二分答案 + 计算几何
对当前二分数值mid的check:
先枚举所有点,看这些点作为圆心,能不能包含其它的点,用状压表示这些点集,储存起来。
接着枚举所有点对,检查这个点对是否可以在mid构成半径的圆上(注意,如果这两个点对可以同时在两个圆上,要作为两种情况分开考虑),如果可以,再看这个圆能不能包含其他的点,用状压表示这些点集,储存起来。
枚举结束后,对状态排序,从高到低枚举每个状态(点集),并消去其子集的标记,如果一个点集有标记,说明这几个点中可以有一个维修点,用addlink()
函数标记一下
然后用dance()
爆搜检查答案已知两个点,一个半径,计算圆心
一开始还因为精度误差不敢用高中方法,后来发现用高中的思路去求就ok了
口述一下:
得到a, b两点的向量,求其法向量,化为单位向量,乘上a,b两点的中点到圆心的距离(用勾股定理),然后a,b两点的中点上下平移那么一个向量就好了
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define MS(x, y) memset(x, y, sizeof(x))
typedef long long LL;
const int MAXN = 20;
const int MAXM = 500;
const double EPS = 1e-7;
struct Node {
double x, y;
};
Node node[MAXN];
int bit[MAXN];
int U[MAXM], D[MAXM], R[MAXM], L[MAXM], Row[MAXM], Col[MAXM];
bool used[MAXN];
int Head[140000], siz[MAXN];
bool vis[140000];
int hsh[140000], hshnum;
int col, tot, limit;
int n;
double dis(Node a, Node b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
Node Circle(Node a, Node b, double r) {
Node temp, ret;
temp.x = -1 * (a.y - b.y);
temp.y = a.x - b.x;
double len = sqrt(temp.x * temp.x + temp.y * temp.y);
temp.x /= len;
temp.y /= len;
double dist = sqrt(r * r - dis(a, b) * dis(a, b) / 4);
if (r < 0) dist = -dist;
ret.x = (a.x + b.x) / 2 + dist * temp.x;
ret.y = (a.y + b.y) / 2 + dist * temp.y;
return ret;
}
void init(int _row, int _col) {
col = _col;
for (int i = 0; i <= col; ++i) {
siz[i] = 0;
U[i] = D[i] = i;
L[i] = i - 1;
R[i] = i + 1;
}
R[col] = 0; L[0] = col;
tot = col;
for (int i = 1; i <= _row; ++i) Head[i] = -1;
}
void addlink(int r, int c) {
++siz[Col[++tot] = c];
Row[tot] = r;
D[tot] = D[c];
U[D[c]] = tot;
U[tot] = c;
D[c] = tot;
if (Head[r] < 0) Head[r] = L[tot] = R[tot] = tot;
else {
R[tot] = R[Head[r]];
L[R[Head[r]]] = tot;
L[tot] = Head[r];
R[Head[r]] = tot;
}
}
void Remove(int c) {
for (int i = D[c]; i != c; i = D[i])
L[R[i]] = L[i], R[L[i]] = R[i];
}
void Resume(int c) {
for (int i = U[c]; i != c; i = U[i])
L[R[i]] = R[L[i]] = i;
}
int left_col() {
int ret = 0;
for (int c = R[0]; c != 0; c = R[c]) used[c] = false;
for (int c = R[0]; c != 0; c = R[c]) if (!used[c]) {
++ret;
used[c] = true;
for (int i = D[c]; i != c; i = D[i])
for (int j = R[i]; j != i; j = R[j])
used[Col[j]] = true;
}
return ret;
}
bool dance(int dep) {
if (dep + left_col() > limit) return false;
if (R[0] == 0) return dep <= limit;
int c = R[0];
for (int i = R[0]; i != 0; i = R[i]) if (siz[i] < siz[c]) c = i;
for (int i = D[c]; i != c; i = D[i]) {
Remove(i);
for (int j = R[i]; j != i; j = R[j]) Remove(j);
if (dance(dep + 1)) return true;
for (int j = L[i]; j != i; j = L[j]) Resume(j);
Resume(i);
}
return false;
}
bool check(double mid) {
// cout<<mid<<endl;
init(1 << n, n);
Node temp1, temp2;
int now;
MS(vis, false);
hshnum = 0;
for (int i = 0; i < n; ++i) {
now = 0;
for (int j = 0; j < n; ++j) if (dis(node[i], node[j]) - mid < EPS) {
now += bit[j];
}
if (!vis[now]) {
vis[now] = true;
hsh[hshnum++] = now;
}
}
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) if (dis(node[i], node[j]) - 2 * mid < EPS) {
temp1 = Circle(node[i], node[j], mid);
temp2 = Circle(node[i], node[j], -mid);
now = (bit[i] | bit[j]);
for (int k = 0; k < n; ++k) if (i != k && j != k) {
if (dis(node[k], temp1) - mid < EPS) {
now |= bit[k];
}
}
if (!vis[now]) hsh[hshnum++] = now;
vis[now] = true;
if (dis(temp1, temp2) > EPS) {
now = (bit[i] | bit[j]);
for (int k = 0; k < n; ++k) if (i != k && j != k) {
if (dis(node[k], temp2) - mid < EPS) {
now |= bit[k];
}
}
if (!vis[now]) hsh[hshnum++] = now;
vis[now] = true;
}
}
}
sort(hsh, hsh + hshnum);
for (int i = hshnum - 1; i >= 0; --i) {
for (int j = 0; j < n; ++j) if ((hsh[i] & bit[j])) {
vis[(hsh[i] ^ bit[j])] = false;
}
if (!vis[hsh[i]]) continue;
vis[hsh[i]] = false;
for (int j = 0; j < n; ++j) if ((hsh[i] & bit[j])) {
addlink(hsh[i], j + 1);
}
}
return dance(0);
}
int main() {
bit[0] = 1;
for (int i = 1; i < MAXN; ++i) bit[i] = bit[i - 1] << 1;
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &limit);
for (int i = 0; i < n; ++i) scanf("%lf%lf", &node[i].x, &node[i].y);
double l = 0, r = 7.1, mid, ans;
while (l - r < EPS) {
mid = (l + r) / 2;
if (check(mid)) {
ans = mid;
r = mid - EPS;
} else l = mid + EPS;
}
printf("%.6f\n", ans + EPS);
}
}