YBTOJ:圈套问题(分治法、鸽笼原理)
生活随笔
收集整理的這篇文章主要介紹了
YBTOJ:圈套问题(分治法、鸽笼原理)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 題目描述
- 數據范圍
- 解析
- 代碼
圖片轉載自: https://blog.csdn.net/weixin_43346722/article/details/118435430
題目描述
平面上有 n個點,用n個大小相同的圓分別將一個點作為圓心,同時滿足圓圈不相交,求圓的最大半徑。
數據范圍
2<=n<=2e52<=n<=2e52<=n<=2e5
解析
把題目抽象一下就是求最小的一對點的距離除以2
考慮如何求呢?
暴力當然是會T飛的
首先把所有點按x排序
然后考慮分治
分治的關鍵是如何把兩個小問題合并
暴力合并還是n方…
我們考慮剪掉一些不必要的比較
設兩邊分別得到的答案的最小值為a
那么x距離大于a的肯定不用比了
但是一旦x的距離全在a里面咋辦?
同理,我們按y再排一下序,y的距離大于a都不用算了
那么每個點對應的的計算范圍大概就是這樣:
那么這樣就不會有很多點了嗎?
我們還有一個了一個關鍵性質:左邊和右邊的點各自之間的距離都不小于a
那么右邊這個矩形里能填的兩兩距離不小于a的點就不多了
關于這個,我們就要使用神奇的鴿巢原理
考慮矩形按照下面這個圖分區:
每個小矩形的對角線長度小于a,所以每個矩形最多有一個點
所以大矩形內的點不超過6個
(同時我們把6個點放到四角和兩長邊的終點,其實也就可以構造出6個的方案)
所以我們每個點需要計算的點最多不超過6個
時間復雜度降為線性,問題得以解決
整體復雜度:nlognnlognnlogn(每次合并按ysort可能再大一些?)
代碼
#include<bits/stdc++.h> using namespace std; const int N=2e5+100; const int M=2e6+100; #define ll long long ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; } int n,m; struct node{double x,y; }p[N],tmp[N],now[N]; bool cmpx(node a,node b){return a.x<b.x;} bool cmpy(node a,node b){return a.y<b.y;} double dis(node a,node b){//printf(" dis:");print(a);print(b);printf("%lf+%lf=%lf")return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void print(node o){printf("(%.2lf %.2lf)",o.x,o.y);} double solve(int l,int r){if(l==r) return 2e9;int mid=(l+r)>>1;double res=min(solve(l,mid),solve(mid+1,r));int num=0,tot=0;for(int i=mid+1;i<=r;i++){if(p[i].x-p[mid].x>=res) break;tmp[++num]=p[i];//printf("tmp:");print(p[i]);putchar('\n');}for(int i=mid;i>=l;i--){if(p[mid+1].x-p[i].x>=res) break;now[++tot]=p[i];//printf("now:");print(p[i]);putchar('\n');}sort(tmp+1,tmp+1+num,cmpy);sort(now+1,now+1+tot,cmpy);int pre=1;for(int i=1;i<=tot&&pre<=num;i++){while(pre<=num&&now[i].y-tmp[pre].y>=res) pre++;for(int j=pre;tmp[j].y-now[i].y<res&&j<=num;j++){//printf("i=%d j=%d dis=%.2lf",i,j,dis(now[i],tmp[j]));print(now[i]);print(tmp[j]);putchar('\n');res=min(res,dis(now[i],tmp[j]));}}return res; } int main(){while(1){n=read();if(n==0) return 0;for(int i=1;i<=n;i++){scanf("%lf%lf",&p[i].x,&p[i].y);}sort(p+1,p+1+n,cmpx);printf("%.2lf\n",solve(1,n)/2);}return 0; } /* 2 0 0 1 1 2 1 1 1 1 3 -1.5 0 0 0 0 1.5 0 */ 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的YBTOJ:圈套问题(分治法、鸽笼原理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 索尼发布全画幅无反相机 A9 III:采
- 下一篇: 腾讯音游《节奏大师》回归首日出现无法进入