日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

YBTOJ:圈套问题(分治法、鸽笼原理)

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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:圈套问题(分治法、鸽笼原理)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。