首页 > 其他分享 >一元三次方程(分治法)

一元三次方程(分治法)

时间:2024-03-16 20:31:31浏览次数:27  
标签:一元 方程 double 分治 问题 区间

目录

题目描述

分治法思想介绍

分治思路

我的代码

总结与展望

一元三次方程求解

【题目描述】

形如:ax^3+bx^2+cx+d=0这样的一个一元三次方程。

给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在−100至100之间),且根与根之差的绝对值≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。

【输入】

一行,包含四个实数a,b,c,d,相邻两个数之间用单个空格隔开。

【输出】

一行,包含三个实数,为该方程的三个实根,按从小到大顺序排列,相邻两个数之间用单个空格隔开,精确到小数点后2位。

【输入样例】

1.0 -5.0 -4.0 20.0

【输出样例】

-2.00 2.00 5.00

分治法思想介绍

分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题性质相同。求出子问题的解后,再合并这些子问题的解得到原问题的解。

分为如下三个步骤,俗称“分解合”:

(1)分解:将原问题分解为若干个规模较小的子问题,这些子问题相互独立,与原问题形式相同

(2)解决:若子问题规模较小而容易被解决则直接解,否则需要继续将子问题分解为更小的子问题,然后递归地解决这些子问题

(3)合并:将各个子问题的解合并为原问题的解

二、分治思路

形如:ax^3+bx^2+cx+d = 0 的一元三次方程组

有如下性质:

              若f(x)=0 ,   那么一定会有  f(L)*f(R)<0

确定根的区间

枚举根的值域中每一个整数 x (-100\leq x\leq 100)

由于根与根之差的绝对值≥1,因此设定搜索区间 [L,R] ,

其中 L=i,R=i+1。若:

⑴     f(L)=0,则确定L为f(x)的根;

⑵     f(L)*f(R)>0,则确定根 x 不在区间[L,R]内,设定 [R,R+1]为下一个 搜索区间 ;

⑶     f(L)*f(R)<0,则确定根x在区间[L,R]内。  

 分治思路:

已经确定根 x 在区间  [L,R]  内(f(L)*f(R)<0),如何在该区间找到根的确切位置?

我们可以不断二分区间,直至找到答案。

取 L 与 R 的中点为 mid

如果  f(L)∗f(mid)<0 , 则根 x 在(L , mid)区间内

同理  f(mid)∗f(R)<0 ,则根 x 在(mid , R)区间内

上述二分过程一直进行到区间的间距满足精度要求为止(R-L<0.001)。此时确定 L 为f(x)的根。

三、我的代码

#include<iostream>
using namespace std;

double a, b, c, d;
//定义一元三次函数f(x)
double f(double x)
{
	return a * x * x * x + b * x * x + c * x + d;
}

//使用二分法查找根
void find(double l, double r)
{
	while (r - l > 0.001)
	{
		double mid = (l + r) / 2;
		if (f(l) * f(mid) <= 0) r = mid;
		else l = mid;
	}
	printf("%.2f ", l);
}

int main()
{
	int cnt = 0;//记录根的数量
	cin >> a >> b >> c >> d;

	//遍历从 -100 到 100 的范围,寻找方程组的根
	for (double i = -100; i <= 100, cnt != 3; i++)
	{
		if (f(i) == 0)
		{
			printf("%.2f ", i);
			cnt++;
			continue;
		}
		else if (f(i) * f(i + 1) < 0)
		{
			find(i, i + 1);
			cnt++;
		}
	}
	return 0;
}

四、总结与展望

题目来源:P1024 [NOIP2001 提高组] 一元三次方程求解 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

算法分析:

时间复杂度  T(n)<=T(n/2)+1    可得  T(n)=\log_{2}n

代码的灵活性:修改cnt(根的数量),可以求解一元三次方程根的所有情况

                         修改循环条件,可以控制查找根的范围

                         修改区间间距,可以控制根的精度

标签:一元,方程,double,分治,问题,区间
From: https://blog.csdn.net/lsfff666/article/details/136768565

相关文章

  • 双曲型偏微分方程的几个概念
    本章研究了一类双曲型偏微分方程的一些基本性质。本书中研究的离散化技术主要基于偏微分方程的基本物理和数学特性。因此,有理由在偏微分方程的一些基础上投入一些精力。这里我们几乎只讨论双曲偏微分方程,特别是双曲守恒律。这主要有三个原因:(i)当忽略粘性和热传导的影响时,可压缩流......
  • Java(计算机相关)面试之海量数据问题处理(1)分治/hash/排序
    原文链接:https://blog.csdn.net/a619602087/article/details/130348569面试的时候经常被问到海量数据处理问题,下面我会分期介绍几种海量数据处理的思路还有案例了解了之后面试不用怕了大数据处理思路:分而治之/Hash映射+HashMap统计+堆/快速/归并排序分而治之/hash映射:......
  • 一阶微分方程
    常数变易法考虑以下一阶线性微分方程\[\dfrac{\text{d}y}{\text{d}x}=P(x)y+Q(x)\]先解齐次方程\[\begin{aligned}\dfrac{\text{d}y}{\text{d}x}&=P(x)y\\\dfrac{\text{d}y}{y}&=P(x)\text{d}x\\\lny&=P_1(x)+C\\y&=C\exp(P_1(x))\end{aligned}\]其......
  • 点分治
    点分治是树分治的一种形式,通常用来求满足某种要求的路径数量。引入有\(n\)个数,问是否存在一个\(l,r\)使得区间和为\(k\),强行用分治做,可以将数组分成两半,递归后处理左边\(l\)右边\(r\),然后就用前缀和加\(map\)加归并的并做就可以了。思路可以将这个思路放到树上,分为......
  • chapter8-递归与分治
    1.递归递归,指直接或间接地调用自身,解决此类题目的方法见我之前走台阶的笔记,重点有2个,(1)分析问题,归纳出递归公式;(2)递归出口。就像俄罗斯套娃一样,要让递归调用总体朝向递归出口推进。n的阶乘//递归-n的阶乘2024-03-08#include<iostream>#include<cstdio>usingnamespaces......
  • 【洛谷】求第k小的数字(分治算法)
    题目描述如题所述,找到n个数中第K小的数字。但是不同的是时间复杂度要求为O(n),也就是说基本上所有的排序算法都不能用了。这里适合的算法是分治法,也就是使用快速排序。因为这道题的一个特点是只需要得到第k小的数字,而并没有说要对所有元素进行排序。如果我们把所有小于某个元素......
  • Educational Codeforces Round 162 E 点分治 虚树 树形dp
    传送门给出\(n\le2\cdot10^5\)的一棵树,每个节点有一个颜色。求出路径长度为\(2\)路径首端和尾端拥有相同颜色,且路径上其他点不存在相同颜色的点的路径条数。当时看错题了,把颜色抽出来后没法做了。后来感觉能点分治,然后把题看对了,遂写了一个极其抽象的点分治。除此之外,把某......
  • 【习题】5.2 一阶常系数线性微分方程组
    [T050201]求方程组\(\begin{cases}x'+y'=y+z\\y'+z'=z+x\\z'+x'=x+y\end{cases}\)的通解.    解将方程组写成矩阵形式:\[\begin{aligned}&\begin{pmatrix}1&1&0\\0&1&1\\1&0&1\end{pmatrix}\begin{pmat......
  • C++ 一元运算符重载
    一元运算符只对一个操作数进行操作,下面是一元运算符的实例:递增运算符(++)和递减运算符(--)一元减运算符,即负号(-)逻辑非运算符(!)一元运算符通常出现在它们所操作的对象的左边,比如!obj、-obj和++obj,但有时它们也可以作为后缀,比如obj++或obj--。下面的实例演示了如何......
  • 点分治学习笔记
    0.前言又称淀粉质。学科营之前赶紧来一波急抓。1.引入我们考虑这样一个问题,对于一棵树,我们求出树上所有路径长度小于等于\(k\)的路径总数。首先不难想到一种\(n^3\)的暴力做法,即枚举两个端点,然后暴力出路径。考虑找路径的时候优化一下,采用倍增或者树链剖分将复杂度变为......