3/29 百度筆試第三題ac代碼

3/29 百度筆試第三題ac代碼
題目
給定M*N的區域,給定一些點的座標代表星球,我們需要儘量避開上下邊界和星球,如果我要從左邊界到右邊界,任意點出發和停止,請問離所有星球和上下邊界的距離的最小值最大是多少?
思路
核心思想就是如果說存在一個半徑r,使得每個星球按這個半徑r畫一個圓時,將會覆蓋從上到下的一整條路徑(路徑堵住了)就認爲走不通

  1. 按y值給點排序,也就是說按星球的縱向座標值給星球排序
  2. 因爲答案是浮點數,一般採用二分法求,我們二分半徑r,最小爲0,最大爲M/2(M/2時將充滿屏幕)
  3. 兩個星球的距離如果小於2r,則認爲這兩個星球合在一起,合在一起的用並查集來維護,這裏注意一點,如果暴力的話時O(N2)就超時了,因爲我們之前排過序,所以對於一個星球我們就可以只找y到y+2r之間的星球(小於y的之前已經算過了,剩下的一定大於2*r)
  4. 如果星球的y值小於2r則認爲星球和下邊界合併了,如果M-y<2r則認爲上邊界和星球合併了
  5. 檢查上和下是否合在一起了,如果上下合併了則可以認爲上下已經打通,左右已經走不通也就是說無法從左到右了
  6. 一直二分直到找到r走得通和走不通的邊界點
#include <map>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std;
using ll=long long;
int find(vector<int> &arr,int index){
    if(arr[index]<0)
        return  index;
    return arr[index]=find(arr,arr[index]);
}
void unino(vector<int> &arr,int index1,int index2){
    if(find(arr,index1)!=find(arr,index2)){
        arr[find(arr,index1)]=find(arr,index2);
    }
}
int main(){
    int N,M,K;
    cin>>N>>M>>K;
    vector<pair<double,double>> plant(K);
    for(int i=0;i<K;i++){
        int r,c;
        cin>>r>>c;
        plant[i].first=c;
        plant[i].second=r;
    }
    sort(plant.begin(),plant.end());
    for(int i=0;i<K;i++){
        swap(plant[i].first,plant[i].second);
    }
    double start=0,end=M*1.0/2;
    while(end-start>1e-6){
        double mid=(end+start)/2;
        vector<int> disjoin_set(K+2,-1);
        for(int i=0;i<K;i++){
            for(int j=i+1;j<K;j++){
                double disx=plant[j].first*1.0-plant[i].first*1.0;
                if(disx>2*mid)
                    continue;
                double disy=plant[j].second*1.0-plant[i].second*1.0;
                if(disy>2*mid)
                    break;
                if(sqrt(disx*disx+disy*disy)<2*mid){
                    unino(disjoin_set,i,j);
                }
            }
            if(plant[i].second*1.0<2*mid){
                unino(disjoin_set,i,K);
            }
            if(M*1.0-plant[i].second*1.0<2*mid){
                unino(disjoin_set,i,K+1);
            }
        }
        if(find(disjoin_set,K)==find(disjoin_set,K+1)){
            end=mid;
        }
        else{
            start=mid;
        }
    }
    printf("%.4lf",(start+end)/2);

}

有評論說第一題,其實很簡單,最小公倍數(A,B)=AB/最大公約數(A,B)
那麼最小公倍數-最大公約數=A
B/(最大公約數)-最大公約數,
這個函數關於AB遞增,關於最大公約數遞減,也就是說我們要AB最大,最大公約數最小
A和A-1一定互素,公約數爲1,A*(A-1)的大小也僅次於AA,所以答案就是A(A-1),注意要用longlong

第二題
https://blog.csdn.net/yhf_naive/article/details/105186292

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章