//POJ 3714 Raid
//AC by warteac
//2013-7-19
/*
法一:先排序,然後依次向後找最小距離,並且剪枝
重點是,不需要指定找 人到站點或是站點到人的距離,把所有的都看成點,就找兩點最短距離即可
爲了區別用flag標記,求距離時判斷flag是否相同。
6764K 3579MS C++ 2090B 2013-07-19 11:44:37
法二:二分是高效算法;
重點是,合併的時候,求最短距離橫跨左右兩邊的情況,有一個剪枝的動作,不加依然會超時,詳見代碼
TLE: 重複調用函數導致超時,不是算法的問題,詳見代碼
6768K 2922MS C++ 2725B 2013-07-19 11:46:29
*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include <iomanip>
#include<algorithm>
using namespace std;
const double eps = 1e-5;
const double MAXLEN = 1000000000.0;
struct posi{
double x;
double y;
bool flag; //0 is agent,1 is raid
};
vector <posi> p;
int num;
double min_length;
double length(posi p1, posi p2){
if(p1.flag != p2.flag)
return sqrt((p2.x - p1.x)*(p2.x - p1.x)+(p2.y - p1.y)*(p2.y - p1.y));
else return MAXLEN;
}
bool cmp(posi p1, posi p2){
if(fabs(p1.x - p2.x) < eps){
return p1.y < p2.y;
}else{
return p1.x < p2.x;
}
}
//////////////////法一/////////////////////////////////
/*double getMinLength(int i){
double min = MAXLEN;
for(int j = i+1; j < 2*num; j++){
if(p[i].flag != p[j].flag){
double temp = length(p[i],p[j]);
if(temp - min < eps){
min = temp;
}
else if(fabs(p[i].x - p[j].x) > min)//如果不加這句if(),有BUG,但POJ沒有檢查出來,具體測試數據見下面
break;
}
}
return min;
}*/
////////////////////法一結束/////////////////////////////
////////////////////法二////////////////////////////////
double getMinLength(int x, int y){
if(y - x <= 2){
double len,minlen = MAXLEN;
for(int i = x; i < y; i++)
for(int j = x+1; j < y; j++){
len = length(p[i],p[j]);
//minlen <?= len;
if(len < minlen) minlen = len;
}
return minlen;
}else{
double r,result = MAXLEN;
int i,j;
int m = (x + y) / 2;//第一步:劃分
//result = getMinLength(x,m) < getMinLength(m,y) ? getMinLength(x,m) : getMinLength(m,y);//第二步:遞歸解決子問題
//TLE: 上式中調用getMinLength()四次,在遞歸次數龐大時就會導致超時了
//解決辦法,用兩個變量Llen,Rlen 保存函數的調用值
double Llen,Rlen;
Llen = getMinLength(x,m);
Rlen = getMinLength(m,y);
result = Llen < Rlen ? Llen : Rlen;//第二步:遞歸解決子問題
for(i = m-1; i >= x; i--){//第三步:合併
if(fabs(p[m].x - p[i].x) > result) break;//剪枝
for(j = m; j < y; j++){
if(fabs(p[m].x - p[j].x) > result) break;//剪枝
r = length(p[i],p[j]);
//result <?= r;
if(result > r) result = r;
}
}
return result;
}
}
/////////////////////法二結束///////////////////////////////
int main(){
int n,i,j;
cin >> n;
while(n--){
posi t;
cin >> num;
p.clear();
min_length = MAXLEN;
for(i = 0; i < num; i++){
cin >> t.x >> t.y;
t.flag = 0;//agent
p.push_back(t);
}
for(i = 0; i < num; i++){
cin >> t.x >> t.y;
t.flag = 1;//raid
p.push_back(t);
}
sort(p.begin(),p.end(),cmp);
//////////////////法一///////////////////////////
/* for(int k = 0 ;k < p.size();k++){
}
for(j = 0; j < 2*num-1; j++){
double mlen = getMinLength(j);
if(mlen < min_length) min_length = mlen;
}*/
//////////////////法一結束/////////////////////////////
//////////////////法二//////////////////////////////
min_length = getMinLength(0,p.size());
//////////////////法二結束//////////////////////////
cout <<setiosflags(ios::fixed);
cout << setprecision(3);
cout << min_length << endl;
}
return 0;
}
/*
測試BUG的數據
INPUT:
1
3
0 0
13 13
15 15
2 5
4 0
4 -6
OUTPUT:(right)
4.000
OUTPUT:(wrong)
5.385
*/