备赛蓝桥杯之二分
3
2 5 8
2
10
5
8
5
https://www.dotcpp.com/oj/problem2926.html
我第一眼看看就是简单的一个二分,然后就迅速写了一下就提交,结果才对了9分。

为什么错呢?我也百思不得其解。看看别人的题解不知道,为什么最后还要判断一下。后来又在网上搜了一下这个题,发现了一个重要的地方。那就是我读题不认真,需要求的是最接近的元素,自然需要进行判断。所以说,下次做题之前要认真读题!!!
来说说思路吧!
首先,咱们为了减少运行时间。把要查找的元素 x 进行一个划分,分为两大类,三小类。两大类是元素 x 是否在序列中。如果不在序列中,直接输出序列中最大/最小的元素即可;在序列中的时候再进行二分即可!如下分为三种情况。
要查找的元素 x 小于序列中的首元素。此时,首元素最接近 x ,输出首元素即可
要查找的元素 x 大于序列中的最后一个元素。此时。最后一个元素最接近 x,输出最后一个元素即可。
要查找的元素在序列里面,再进行二分操作。
当 | q[ l - 1] - x | < | q[ l ] - x | 时,表示 q[l - 1] 最接近 x ,输出 q[l-1]即可。 当 | q[ l - 1] - x | = | q[ l ] - x | 时,由于题目要求多个值满足时,输出最小值即可。所以输出 q[ l - 1 ] 即可。 当 | q[ l - 1] - x | > | q[ l ] - x | 时,表示 q[ l ] 最接近 x ,输出 q[ l ] 即可。
int l = 0,r = n - 1;
while(l < r)
{
int mid = (l + r) / 2;
if(q[mid] >= x)
r = mid;
else
l = mid + 1;
}
int l = 0,r = n - 1;
while(l < r)
{
int mid = (l + r + 1) / 2;
if(q[mid] <= x)
l = mid;
else
r = mid - 1;
}
#include<iostream>
#include <cmath>
using namespace std;
const int N = 1e5 + 10;
int q[N],n,m;
int main()
{
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&q[i]);
scanf("%d",&m);
int x;
while(m--)
{
scanf("%d",&x);
if(x <= q[0])
printf("%d\n",q[0]);
else if(x >= q[n - 1])
printf("%d\n",q[n - 1]);
else
{
int l = 0,r = n - 1;
while(l < r)
{
int mid = (l + r) / 2;
if(q[mid] >= x)
r = mid;
else
l = mid + 1;
}
if(abs(q[l] - x) < abs(q[l - 1] - x))
printf("%d\n",q[l]);
else
printf("%d\n",q[ l - 1]);
}
}
return 0;
}
#include<iostream>
#include <cmath>
using namespace std;
const int N = 1e5 + 10;
int q[N],n,m;
int main()
{
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&q[i]);
scanf("%d",&m);
int x;
while(m--)
{
scanf("%d",&x);
if(x <= q[0])
printf("%d\n",q[0]);
else if(x >= q[n - 1])
printf("%d\n",q[n - 1]);
else
{
int l = 0,r = n - 1;
while(l < r)
{
int mid = (l + r + 1) / 2;
if(q[mid] <= x)
l = mid;
else
r = mid - 1;
}
if(abs(q[l] - x) <= abs(q[l + 1] - x))
printf("%d\n",q[l]);
else
printf("%d\n",q[ l + 1]);
}
}
return 0;
}
https://blog.csdn.net/lq1990717/article/details/124441505
其实也没有什么难的,有两个需要注意的点。
第一个是控制小数点的位数,while循环的条件是 r - l >1e-8。至于为什么请看之前的文章实数二分。
第二个是二分的条件。什么情况需要二分哪一个区间。对于这个求函数的零点,咱们需要知道一个定理就是零点存在定理。
https://baike.baidu.com/item/%E5%8B%98%E6%A0%B9%E5%AE%9A%E7%90%86?fromtitle=%E9%9B%B6%E7%82%B9%E5%AD%98%E5%9C%A8%E5%AE%9A%E7%90%86&fromid=23707175&fromModule=lemma_search-box
内容:函数在一个区间(a,b)上连续,且 f(a) * f(b) < 0,表明这个区间一定存在一个零点!
#include <iostream>
#include <cmath>
using namespace std;
double function(double x)
{
return pow(x,5) - 15 * pow(x,4) + 85 * pow(x,3 ) - 225 * pow(x,2) + 274 * x - 121;
}
int main()
{
double l = 1.5,r = 2.4;
while(r - l > 1e-8)
{
double mid = (l + r) / 2;
if(function(l) * function(mid) < 0)// 表明[l,mid]存在零点
r = mid;// 更新区间方式
else// 否则[mid,r]里面存在零点
l = mid;
}
printf("%lf\n",l);
return 0;
}

添加 家长论坛微信
全部 0条评论