题解:P10459 Raid
思路
这个题其实就是平面最近点对,除了要求特工与能源的最小距离之外,其他地方都一样(致敬人类智慧)。
所以我们考虑分治做法,分别求出分开点坐标左边与右边的最小值再合并,列出坐标,最后再算出距离。
可定义函数
再在
最后,在记录的点中遍历,再找出最小值,返回最小值即可。
与平面最近点对不同的是,它要求特工与能源最小距离而不是任意两点的最小距离,因此我们可以在结构体中定义
code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define N 200005
const double inf=1e12;
int n,b[N],t;
struct node{
double x,y;
int f;
}e[N];
struct edge{
double x,y;
}tmp[N];
double cal(int i,int j){
if(e[i].f==e[j].f) return inf;
return sqrt(pow(e[i].x-e[j].x,2)+pow(e[i].y-e[j].y,2));
}
bool cmp(node a,node b){
return a.x<b.x;
}
bool cmp2(edge i,edge j){
return i.y<j.y;
}
double solve(int l,int r){
if(l>=r) return inf;
if(l+1==r) return cal(l,r);//sqrt(pow(e[l].x-e[r].x,2)+pow(e[l].y-e[r].y,2));
int mid=(l+r)/2,cnt=0;
double t=e[mid].x;
double d=min(solve(l,mid),solve(mid+1,r));
for(int i=l;i<=r;i++){
if(fabs(e[i].x-t)<d){
b[++cnt]=i;
}
}
sort(b+1,b+cnt+1);
for(int i=1;i<=cnt;i++){
for(int j=i+1;j<=cnt&&abs(e[b[j]].y-e[b[i]].y)<=d;j++){
d=min(d,cal(b[i],b[j]));
}
}
return d;
}
int main(){
ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n;
memset(tmp,0,sizeof(tmp));
for(int i=1;i<=n;i++){
cin>>e[i].x>>e[i].y;
e[i].f=0;
}
for(int i=n+1;i<=2*n;i++){
cin>>e[i].x>>e[i].y;
e[i].f=1;
}
sort(e+1,e+2*n+1,cmp);
printf("%.3lf\n",solve(1,2*n));
}
return 0;
}