二分查找刷题3---一元三次方程求解

 题目来源:

        1、[NOIP2001 提高组] 一元三次方程求解 - 洛谷 

        2、《深入浅出程序设计竞赛--基础篇》------汪楚奇P183

解题思路:

1、暴力求解

先不说三次方程的求解方法,本题直接用暴力求解也是可以得到答案的。我们可以直接遍历[-100, 100] 范围内的每个可能的浮点数值,并检查哪些值使得方程的结果接近于零。由于题目要求根与根之间的差的绝对值至少为 1,所以我们可以选一个较小的步长(例如,0.01)在这个范围内进行遍历,每次计算方程在该点的值,如果值接近于零,则认为找到了一个根。22、

#include 
#include 
#include 

using namespace std;

#define EPS 0.01  //设置步长

double f(double a, double b, double c, double d, double x) {
    return a * x * x * x + b * x * x + c * x + d;
}

int main() {
    double a, b, c, d;
    cin >> a >> b >> c >> d;

    for (double i = -100; i <= 100; i += EPS) {
        if (fabs(f(a, b, c, d, i)) < EPS) {
            cout << fixed << setprecision(2) << i << " ";
            i += 1.0 - EPS; // 跳过与这个根相近的一些值,避免找到重复值并跳过绝对值小于1的值
        }
    }

    return 0;
}

 2、用二分查找

使用二分查找是为了降低时间复杂度,其实也就是遍历根在[-100,100]之间用二分搜索找值。

步骤如下:

1、对于 -100 到 100 之间的每个整数 i,检查区间 [i, i+1] 是否包含一个根。我们可以通过检查 f(i)f(i+1) 的符号是否不同来确定这一点。

2、如果 [i, i+1] 区间内存在根,我们可以在这个区间内进行更精细的搜索(例如,使用二分搜索)以找到根的近似位置。

书上的示例代码如下:

#include 
#include 
#include 

using namespace std;

#define eps 1e-4
double A, B, C, D;
double f(double x) {
	return A * x * x * x + B * x * x + C * x + D;
}

int main() {
	cin >> A >> B >> C >> D;
	for (int i = -100; i <= 100; i++) {
		double L = i, R = i + 1, mid; //这里只处理区间[L,R)上的根
		if (fabs(f(L)) < eps) {//如果L是根,可以直接输出
			printf("%.2lf ", L);
		}
		else if (fabs(f(R)) < eps) {//如果R是根,跳过
			continue; // 如果 R 是根,则在下一次迭代中处理
		}
		else if (f(L) * f(R) < 0) {//在(L,R)上有根,执行二分
			while (R - L > eps) {
				mid = (L + R) / 2;
				if (f(mid) * f(R) > 0) {
					R= mid; //如果f(mid)和f(R)正负性相同,那么零点在mid左侧
				}
				else {
					L = mid;//否则在另一侧
				}
			}
			printf("%.2lf ", L);
		}
	}
	return 0;
}

你可能感兴趣的:(算法,数据结构)