20241029每日一题洛谷P1024

普及-每日一题洛谷P1024

有形如:\(a x^3 + b x^2 + c x + d = 0\) 这样的一个一元三次方程。给出该方程中各项的系数(\(a,b,c,d\) 均为实数),并约定该方程存在三个不同实根(根的范围在 \(-100\)\(100\) 之间),且根与根之差的绝对值 \(\ge 1\)。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 \(2\) 位。

提示:记方程 \(f(x) = 0\),若存在 \(2\) 个数 \(x_1\)\(x_2\),且 \(x_1 < x_2\)\(f(x_1) \times f(x_2) < 0\),则在 \((x_1, x_2)\) 之间一定有一个根。

输入

一行,\(4\) 个实数 \(a, b, c, d\)

输出

一行,\(3\) 个实根,从小到大输出,并精确到小数点后 \(2\) 位。

样例输入

1 -5 -4 20

样例输出

-2.00 2.00 5.00

经典的二分求值问题,这道题题目限制了根的范围:根与根之差的绝对值 \(\ge 1\)根的范围在 \(-100\)\(100\) 之间

于是,我们的大致流程就是:

  • 通过\(f(x_1) \times f(x_2) < 0\),寻找到一个区间\((x_1, x_2)\)使得其中必存在一个根

  • 由于根与根之差的绝对值 \(\ge 1\) ,所以寻找区间时,可以以 \(1\) 作为一个跨度

  • 再使用二分法,在含根区间内找到一个近似根

  • 题目要求:精确到小数点后 \(2\),这就存在两种找到根的途径:

    • 二分的mid代入方程中,直接可解出 0

    • 通过左边界l和右边界r向根无限逼近,存在一个精度限制

      通过题目可知:精度需要在小数点后两位,所以在逼近根的时候,只需要控制左边界和右边界的差小于等于\(0.001\)

      这时不妨举例有:\(l=1.005,r=1.006,root=1.00\) 任意选取l或r作为近似根,保留两位小数后,与根的大小几乎相同,可以认为找到了一个根

代码首先实现\(f(x)\)的操作:

double fx(double x) {
	return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}

构建fx函数,方便之后调用求值

然后实现在区间内寻找根的函数find

double find(double l, double r) {
	while (r-l>0.001)//控制近似根的误差小于等于0.001
	{
		double mid = (l + r) / 2;
		if (fx(l) * fx(mid) <= 0)
			r = mid;
		else
			l = mid;
	}
	return l;//返回l或r都可以
}

最后执行在\([-100,100]\)之间寻找含根区间:

for (int i = -100; i <= 100; i++) {
	double l = i, r = i + 1;
	double x1 = fx(l), x2 = fx(r);
	if (x1 == 0) {//判断端点值是否恰好为根
		printf("%.2lf ", l);
		cnt++;
		continue;
	}//只用判断左端点
	if (x1 * x2 < 0) {
		printf("%.2lf ", find(x1,x2));
		cnt++;//记录根的个数
	}
	if (cnt == 3) return 0;//根全部解完后直接退出
}

完整AC代码:

double a, b, c, d;
double fx(double x) {
	return a * pow(x, 3) + b * pow(x, 2) + c * x + d;
}

double find(double l, double r) {
	while (r-l>0.001)
	{
		double mid = (l + r) / 2;
		if (fx(l) * fx(mid) < 0)
			r = mid;
		else
			l = mid;
	}
	return l;
}

int main()
{
	scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
	int cnt = 0;
	for (int i = -100; i <= 100; i++) {
		double l = i, r = i + 1;
		double x1 = fx(l), x2 = fx(r);
		if (x1 == 0) {
			printf("%.2lf ", l);
			cnt++;
			continue;
		}
		if (x1 * x2 <= 0) {
			printf("%.2lf ", find(x1,x2));
			cnt++;
		}
		if (cnt == 3) return 0;
	}
	return 0;
}
posted @ 2024-11-02 15:40  才瓯  阅读(59)  评论(0)    收藏  举报