引用:https://baike.baidu.com/item/%E4%BA%8C%E5%88%86%E6%B3%95/1364267?fr=aladdin
二分法
对于区间上连续不断且的函数,通过不断地把函数的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
定义
二分法(Bisection method) 即一分为二的方法. 设为R的闭区间. 逐次二分法就是造出如下的区间序列,,且对任一自然数,或者等于,或者等于,其中表示的中点。
典型算法
算法:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。
基本思想:假设数据是按升序排序的,对于给定值,从序列的中间位置k开始比较,
如果当前位置值等于,则查找成功;
若小于当前位置值,则在数列的前半段中查找,;
若大于当前位置值,则在数列的后半段中继续查找,
直到找到为止,时间复杂度:
求法
给定精确度,用二分法求函数零点近似值的步骤如下:
1 确定区间,验证,给定精确度.
2 求区间的中点.
3 计算.
(1) 若,则就是函数的零点;
(2) 若,则令;
(3) 若,则令.
(4) 判断是否达到精确度:即若,则得到零点近似值(或),否则重复2-4.
例题
Oj Url:http://noi.openjudge.cn/ch0111/02/
http://noi.openjudge.cn/ch0111/01/
01:二分法求函数的零点
总时间限制: 1000ms
内存限制: 65536kB
描述
有函数:
已知 , 且方程 在区间 有且只有一个根,请用二分法求出该根。
输入 无
输出 该方程在区间 中的根。要求四舍五入到小数点后6位。
样例输入 无
样例输出 不提供
程序代码
#include <iostream>
#include <iomanip>
#include <cmath>
typedef double db;
inline bool determine(const db mid) {
db f = pow(mid, 5) - 15.0 * pow(mid, 4) + 85.0 * pow(mid, 3) - 225.0 * pow(mid, 2) + 274.0 * mid - 121.0;
return f > 0.0;
};
int main(int argc, char *argv[]) {
std::ios::sync_with_stdio(false);
db left = 1.5, right = 2.4, mid;
while (right - left > 1e-8) {
mid = left + (right - left) / 2.0;
if (determine(mid)) left = mid;
else right = mid;
};
std::cout << std::fixed << std::setprecision(6) << mid << std::endl;
return 0;
};
02:查找最接近的元素
总时间限制: 1000ms
内存限制: 65536kB
描述
在一个非降序列中,查找与给定值最接近的元素。
输入
第一行包含一个整数,为非降序列长度。。
第二行包含个整数,为非降序列各元素。所有元素的大小均在之间。
第三行包含一个整数,为要询问的给定值个数。。
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在之间。输出
行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。
样例输入
3 2 5 8 2 10 5
样例输出
8 5
程序代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int INF = 0x3ffffff;
const int MAX_SIZE = 1000001;
int array[MAX_SIZE] = {};
template <typename _Tp>
inline void quicksort(_Tp *arr, int start, int end) {
int i = start, j = end; _Tp pivot = arr[start];
if (i >= j) return;
while (i != j) {
while (i < j && arr[j] > pivot) --j;
while (i < j && arr[i] < pivot) ++i;
if (i < j) swap(arr[i], arr[j]);
};
swap(arr[i], arr[start]);
quicksort(arr, start, i - 1);
quicksort(arr, i + 1, end);
};
int main(int argc, char *argv[]) {
int n; cin >> n;
for (int i = 0; i < n; ++i) scanf("%d", array + i);
int m; cin >> m;
while (m--) {
int bf, answer, left = 0, mid, right = n - 1; cin >> bf;
if (bf <= array[0]) {cout << array[0] << endl; continue;};
if (bf >= array[n - 1]) {cout << array[n - 1] << endl; continue;};
while (left <= right) {
mid = left + (right - left) / 2;
if(array[mid] <= bf) left = mid + 1;
else right = mid - 1;
};
if (abs(array[left] - bf) < abs(array[right] - bf)) answer = left;
else answer = right;
cout << array[answer] << endl;
};
return 0;
};