ch_g

ECUST_ACMer —— ch_g
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[HDU][3124][Moonmist][最近圆对问题(二分 + 扫描线)]

Posted on 2011-03-12 11:16  ch_g  阅读(816)  评论(0编辑  收藏  举报
/*
题目:Moonmist
题目来源:HDU 3124 (2009 Asia Wuhan Regional Contest Online)
题目难度:中等偏难
题目内容或思路:
最近圆对
二分 + 扫描线
一道很不错的题目,不过OJ上数据比较弱,一些有问题的代码也能AC
解题报告:
http://blog.sina.com.cn/s/blog_64675f540100o02x.html
做题日期:2011.3.12
*/
#include
<cstdio>
#include
<cstdlib>
#include
<climits>
#include
<iostream>
#include
<algorithm>
#include
<cstring>
#include
<string>
#include
<queue>
#include
<map>
#include
<vector>
#include
<bitset>
#include
<cmath>
#include
<set>
#include
<utility>
#include
<ctime>
#define sqr(x) ((x)*(x))
using namespace std;

const int N = 50010;
const double eps = 1e-8;
int n, lft[N], rht[N];
set<int> s;

struct circle {
double x, y, r;
}cir[N];

int dcmp(double x) {
if (x < -eps) return -1; else return x > eps;
}

double dis(circle a, circle b) {
return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y)) - a.r - b.r;
}

bool cmp(circle a, circle b) {
return a.y < b.y;
}

bool cmp2(int i, int j) {
return cir[i].x - cir[i].r < cir[j].x - cir[j].r;
}

bool cmp3(int i, int j) {
return cir[i].x + cir[i].r < cir[j].x + cir[j].r;
}

bool inter(circle a, circle b, double delta) {
return dcmp(dis(a, b) - delta * 2) < 0;
}

bool insert(int i, double mid) {
set<int>::iterator it = s.insert(lft[i]).first;
if (it != s.begin()) {
if (inter(cir[*--it], cir[lft[i]], mid))
return false;
++it;
}
if (++it != s.end() && inter(cir[*it], cir[lft[i]], mid))
return false;
return true;
}

bool remove(int j, double mid) {
set<int>::iterator it = s.find(rht[j]);
if (it != s.begin() && it != --s.end()) {
int a = *--it; ++it;
int b = *++it;
if (inter(cir[a], cir[b], mid))
return false;
}
s.erase(rht[j]);
return true;
}

bool check(double mid) {
s.clear();
for (int i = 0, j = 0; i < n || j < n;) {
if (j == n) {
if (!insert(i++, mid)) return false;
}
else if (i == n) {
if (!remove(j++, mid)) return false;
}
else if (dcmp(cir[lft[i]].x - cir[lft[i]].r - mid
- cir[rht[j]].x - cir[rht[j]].r - mid) <= 0) {
if (!insert(i++, mid)) return false;
}
else {
if (!remove(j++, mid)) return false;
}
}
return true;
}

void solve() {
scanf(
"%d", &n);
for (int i = 0; i < n; ++i) {
scanf(
"%lf%lf%lf", &cir[i].x, &cir[i].y, &cir[i].r);
lft[i]
= rht[i] = i;
}
sort(cir, cir
+ n, cmp);
sort(lft, lft
+ n, cmp2);
sort(rht, rht
+ n, cmp3);
double mid, low = 0, high = dis(cir[0], cir[1]) / 2;
while (dcmp(high - low)) {
mid
= (high + low) / 2;
if (check(mid)) low = mid;
else high = mid;
}
printf(
"%lf\n", low + high);
}

int main() {
#ifndef ONLINE_JUDGE
freopen(
"D:\\in.txt", "r", stdin);
#endif
int cas;
scanf(
"%d", &cas);
while (cas--) {
solve();
}
return 0;
}