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

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值