原题链接:蓝桥杯算法提高-两条直线
解题思路:
这题有一定的难度 需要一定的时间来理解
参考代码:
#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;
}0.0分
2 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复