【题解】袭击(平面最近点对)

题目描述
在与联盟的战斗中屡战屡败后,帝国撤退到了最后一个据点。

依靠其强大的防御系统,帝国击退了联盟的六波猛烈进攻。

经过几天的苦思冥想,联盟将军亚瑟终于注意到帝国防御系统唯一的弱点就是能源供应。

该系统由N个核电站供应能源,其中任何一个被摧毁都会使防御系统失效。

将军派出了N个特工进入据点之中,打算对能源站展开一次突袭。

不幸的是,由于受到了帝国空军的袭击,他们未能降落在预期位置。

作为一名经验丰富的将军,亚瑟很快意识到他需要重新安排突袭计划。

他现在最想知道的事情就是哪个特工距离其中任意一个发电站的距离最短。

你能帮他算出来这最短的距离是多少吗?

输入格式
输入中包含多组测试用例。

第一行输入整数T,代表测试用例的数量。

对于每个测试用例,第一行输入整数N。

接下来N行,每行输入两个整数X和Y,代表每个核电站的位置的X,Y坐标。

在接下来N行,每行输入两个整数X和Y,代表每名特工的位置的X,Y坐标。

输出格式
每个测试用例,输出一个最短距离值,结果保留三位小数。

每个输出结果占一行。

solution:

分治+二分(最近点对问题)
算法分析:这是一道经典的最近点对问题的模板,这里略微讲述一下这种问题的解法,首先呢,我们将这些点的 x x x坐标,为第一关键字, y y y坐标为第二关键字,从小到大排序,接着我们取一个中点 m i d mid mid点,将 m i d mid mid点左边的点,统统归为平面 d 1 d1 d1,然后 m i d mid mid点右边的点统统归为平面 d 2 d2 d2如下图所示。

在这里插入图片描述
然后在如图所示的左右均 d / 2 d/2 d/2区域中,再按 y y y为关键字排序。再暴力枚举。注意可以剪枝。

时间复杂度是 O ( n l o g n l o g n ) O(nlognlogn) O(nlognlogn)。优化主要是在跨区间的寻找上,可以省掉不少的枚举时间。
在这里插入图片描述

#include<bits/stdc++.h> using namespace std; const int N=1e5+5; const int inf=0x3f3f3f3f; inline int read() { int X=0; bool flag=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();} while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();} if(flag) return X; return ~(X-1); } struct node { double x,y; int f; }a[N],b[N],t[N]; double dist(int l,int r) { if(a[l].f==a[r].f) return inf; return sqrt((a[l].x-a[r].x)*(a[l].x-a[r].x)+(a[l].y-a[r].y)*(a[l].y-a[r].y)); } int T,n; bool cmp(node A,node B) { return A.y<B.y; } bool cmp2(node A,node B) { return A.x<B.x; } double dfs(int l,int r) { if(l+1>=r) return inf; int mid=(l+r)>>1,cnt=0; double res=min(dfs(l,mid),dfs(mid,r)); int i=l,j=mid,num=l; while(i<mid||j<r) { if(i==mid) b[num++]=a[j++]; else if(j==r) b[num++]=a[i++]; else if(a[i].y<a[j].y) b[num++]=a[i++]; else b[num++]=a[j++]; } for(int i=l;i<=r;i++) a[i]=b[i]; for(int i=mid-1;i>=l;i--) if(a[mid].x-a[i].x<res) t[++cnt]=a[i]; for(int i=mid;i<r;i++) if(a[i].x-a[mid].x<res) t[++cnt]=a[i]; for(int i=1;i<=cnt;i++) for(int j=i+1;j<=cnt&&t[j].y-t[i].y<res;j++) { if(t[i].f==t[j].f) continue; res=min(res,sqrt((t[i].x-t[j].x)*(t[i].x-t[j].x)+(t[i].y-t[j].y)*(t[i].y-t[j].y))); } return res; } signed main() { T=read(); while(T--) { n=read(); for(int i=1;i<=n;i++) { scanf("%lf%lf",&a[i].x,&a[i].y); a[i].f=0; } for(int i=n+1;i<=2*n;i++) { scanf("%lf%lf",&a[i].x,&a[i].y); a[i].f=1; } sort(a+1,a+1+2*n,cmp2); printf("%.3lf\n",dfs(1,1+2*n)); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530389.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(26)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示