洛谷千题详解 | P1024 [NOIP2001 提高组] 一元三次方程求解【C++、Java语言】

博主主页:Yu·仙笙

专栏地址:洛谷千题详解

目录

题目描述

输入格式

输出格式

输入输出样例

说明/提示

解析:

C++源码:

C++源码2:

Java源码:


 --------------------------------------------------------------------------------------------------------------------------------

题目描述

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

提示:记方程 f(x) = 0f(x)=0,若存在 22 个数 x_1x1​ 和 x_2x2​,且 x_1 < x_2x1​<x2​,f(x_1) \times f(x_2) < 0f(x1​)×f(x2​)<0,则在 (x_1, x_2)(x1​,x2​) 之间一定有一个根。

--------------------------------------------------------------------------------------------------------------------------------

输入格式

一行,4 个实数 a, b, c, d

--------------------------------------------------------------------------------------------------------------------------------

输出格式

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

--------------------------------------------------------------------------------------------------------------------------------

输入输出样例

输入 #1复制

1 -5 -4 20

输出 #1复制

-2.00 2.00 5.00

说明/提示

【题目来源】

NOIP 2001 提高组第一题

--------------------------------------------------------------------------------------------------------------------------------

解析:

导数+勘根定理+牛顿迭代.

先对函数求导,f'(x)=3ax^2+2*bx+c.

然后直接求根公式求f'(x)=0的点,也就是函数极点.

(我们可以顺便求一下凸形函数极值hhh)

这题保证有三个不定根,所以有两个单峰.

我们分别设这两个点为p,q.

然后显然的必有三个根在[-100,p),[p,q],(q,100]三个区间内 (两极点间必定存在零点,勘根定理).

然后用神奇的牛顿迭代法多次迭代就好了.

证明请自行百度,本蒟蒻只能感性的认识orz.

--------------------------------------------------------------------------------------------------------------------------------

C++源码:

#include<iostream>
#include<cstdio>
#include<cmath>
#define eps 1e-4
using namespace std;
double x1,x2,x3,a,b,c,d;
double f(double x){return a*x*x*x+b*x*x+c*x+d;}
double df(double x){return 3*a*x*x+2*b*x+c;}
double slove(double l,double r)
{
	double x,x0=(l+r)/2;
	while(abs(x0-x)>eps)
	  x=x0-f(x0)/df(x0),swap(x0,x);
	return x;
}
int main()
{
	cin>>a>>b>>c>>d;
	double p=(-b-sqrt(b*b-3*a*c))/(3*a);
	double q=(-b+sqrt(b*b-3*a*c))/(3*a);
	x1=slove(-100,p),x2=slove(p,q),x3=slove(q,100);
	printf("%.2lf %.2lf %.2lf",x1,x2,x3);
	return 0;
}

--------------------------------------------------------------------------------------------------------------------------------

C++源码2:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
double f(double x,double a,double b,double c,double d)//用于计算三次函数值
{
    return a*x*x*x+b*x*x+c*x+d;
}
double solve(double a,double b,double c,double d,double x0,double x1)//割线法求解
{
    double xx[2]={x0,x1};//用xx数组滚动存储结果
    int flag=0;
    while(abs(xx[0]-xx[1])>1e-4)//控制精度
    {
        xx[flag]=xx[flag]-f(xx[flag],a,b,c,d)/((f(xx[flag],a,b,c,d)-f(xx[flag^1],a,b,c,d)))*(xx[flag]-xx[flag^1]);
        flag^=1;
    }
    return xx[0];
}

double a,b,c,d,x[3]={-1000,-1000,-1000};
int tot;

bool check(double xx)//判断是否为新的解
{
    bool flag=0;
    for(int i=0;i<3;++i)flag|=abs(xx-x[i])<0.5;
    return !flag;
}

int main()
{
    scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
    for(double i=-100;i<=100;i+=0.5)//注意这里以0.5为步长枚举。我一开始步长为一,结果有一个点答案有1.0,2.0,直接除以零GG
    {//当然你也可以在除以零时特判,但我懒得写了
        double xx=solve(a,b,c,d,i,i+0.5);
        if(check(xx))x[tot++]=xx;
    }
    sort(x,x+3);//不要忘记从小到大排序 //我太懒了QAQ
    for(int i=0;i<3;++i)printf("%.2lf ",x[i]);
}

--------------------------------------------------------------------------------------------------------------------------------

Java源码:

import java.util.*;                   // P1024 [NOIP2001 提高组] 一元三次方程求解
public class Main{                    // 暴力枚举
public static void main(String[] args){
   Scanner rd=new Scanner(System.in); 
   double a=rd.nextDouble();
   double b=rd.nextDouble();
   double c=rd.nextDouble();
   double d=rd.nextDouble();
   for(double i=-100;i<=100;i+=0.001) {   //数据范围从-100到100
	   double j=i+0.001;
	   double y1=a*i*i*i+b*i*i+c*i+d;
	   double y2=a*j*j*j+b*j*j+c*j+d;
	   if(y1>=0&&y2<=0||y1<=0&&y2>=0) {    若存在两个数y1,y2且y1<y2,f(y1)*f(y2)<0 则方程解肯定在y1~y2范围内   基本数学原理
		  double  x=(i+j)/2;
		   System.out.print(String.format("%.2f", x)+" ");
	   }
   }
}
}

--------------------------------------------------------------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/djfihhfs/article/details/128453300