蓝桥杯真题算法提高-两条直线

题目描述

给定平面上n个点。
求两条直线,这两条直线互相垂直,而且它们与x轴的夹角为45度,并且n个点中离这两条直线的曼哈顿距离的最大值最小。
两点之间的曼哈顿距离定义为横坐标的差的绝对值与纵坐标的差的绝对值之和,一个点到两条直线的曼哈顿距离是指该点到两条直线上的所有点的曼哈顿距离中的最小值。

 

输入

第一行包含一个数n。 

接下来n行,每行包含两个整数,表示n个点的坐标(横纵坐标的绝对值小于10^9)。 

数据规模与约定
对于30%的数据,n< =100。
对于另外30%的数据,坐标范的绝对值小于100。
对于100%的数据,n< =10^5。
 

输出

输出一个值,表示最小的最大曼哈顿距离的值,保留一位小数。  

样例输入复制

4
1 0
0 1
2 1
1 2

样例输出复制

1.0
#include<iostream>  
#include<algorithm>  
#include<cstdio>  
#include<cmath>  
using namespace std;  
   
const int N=100000;  
struct P{int x,y;};  
bool cmp(P a,P b){  
    if(a.x==b.x)return a.y<b.y;  
    return a.x<b.x;  
}  
P d[N+5];  
struct F{int max,min;};  
F fl[N+5],fr[N+5];  
inline double Max(double a,double b){return a>b?a:b;}  
inline double Min(double a,double b){return a>b?b:a;}  
bool check(double m,int n){  
    m*=2;  
    int i,j=0;  
    for(i=0;i<n;i++){  
        while(j<n&&d[j].x-d[i].x<=m)j++;  //找出最大的xj使xj-xi<=m,所以在xi到xj的这段区间的范围
是垂直线的范围之后找出[1,i-1]以及[j+1,n-1]范围内的最大的y和最小的y值,如果最大的y值减去最小的y值<=m,
则说明这是水平线的范围,则进行下一轮二分找出中点,找出更优解。
        double MAX=-1e10;  
        double MIN=1e10;  
        if(j!=n){  
            MAX=Max(MAX,fr[j].max);  
            MIN=Min(MIN,fr[j].min);  
        }  
        if(i-1>=0){  
            MAX=Max(MAX,fl[i-1].max);  
            MIN=Min(MIN,fl[i-1].min);  
        }  
     //   cout<<i<<" "<<j<<" "<<MAX<<" "<<MIN<<endl;  
        if(MAX-MIN<=m)return true;  
    }  
    return false;  
}  
void init(int n){  
    int i;  
    fl[0].min=fl[0].max=d[0].y;  
    for(i=1;i<n;i++){  
        fl[i].max=Max(fl[i-1].max,d[i].y); //fl[i]代表着前i个y坐标里面的最大值, 
        fl[i].min=Min(fl[i-1].min,d[i].y); //fl[i]代表着前i个y坐标里面的最小值。 
    }  
    fr[n-1].min=fr[n-1].max=d[n-1].y;  
    for(i=n-2;i>=0;i--){  
        fr[i].max=Max(fr[i+1].max,d[i].y); //fr[i]代表着后(n-i)个y坐标里面的最大值 
        fr[i].min=Min(fr[i+1].min,d[i].y);  //fr[i]代表着后(n-i)个y坐标里面的最小值 
    }  
}  
int main(){  
    int i,n;  
    cin>>n;  
    for(i=0;i<n;i++){  
        int x,y;  
        scanf("%d%d",&x,&y);  
        d[i].x=x+y;   
        d[i].y=x-y;  //将坐标轴按顺时针旋转45度。 
    }  
    sort(d,d+n,cmp);  //按x坐标从小到大的顺序排序 
    init(n);  
    double l=0.0;  
    double r=1000000000;  
    while(r-l>=0.01){  
        double m=(l+r)/2; //二分法判断答案
      //  cout<<m<<endl;  
        if(check(m,n))r=m;  
        else l=m;  
    }  
    printf("%.1f\n",r);  //分到不能再分之后 得出答案即为最小的最大的曼哈顿距离
    return 0;  
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值