NOIP2001 一元三次方程求解[導數+牛頓迭代法]


題目描述

有形如:ax3+bx2+cx+d=0 這樣的一個一元三次方程。給出該方程中各項的系數(a,b,c,d 均為實數),並約定該方程存在三個不同實根(根的范圍在-100至100之間),且根與根之差的絕對值>=1。要求由小到大依次在同一行輸出這三個實根(根與根之間留有空格),並精確到小數點后2位。

提示:記方程f(x)=0,若存在2個數x1和x2,且x1<x2,f(x1)*f(x2)<0,則在(x1,x2)之間一定有一個根。

輸入輸出格式

輸入格式:

 

一行,4個實數A,B,C,D。

 

輸出格式:

 

一行,三個實根,並精確到小數點后2位。

 

輸入輸出樣例

輸入樣例#1:
1 -5 -4 20
輸出樣例#1:
-2.00 2.00 5.00


數據規模太小,可以隨便暴力

但為了證明我這幾天微積分沒白學,用一個高級的方法
首先 f(x)=ax3+bx2+cx+d 求導得到 df/dx=3ax2+2bx+c
求這個導數的零點(就是二次函數求根公式了)得到f(x)的最值點
最值點組成的三個區間一定各有一個f(x)零點,使用牛頓迭代法求得這個零點即可
牛頓迭代法就是不停的用一個點的切線擬合曲線,那個點的導數就是切線斜率

依次類推,可以得到求高次函數零點的一種迭代法:
求n次函數零點,需要極值點來划分區間,也就需要求其導數(n-1次函數)的零點,依次迭代到n=2直接通過公式(當然n=3或4也可以)
最后的復雜度依賴於求零點算法的復雜讀
貌似沒有人發表過,那么就叫Candy迭代法
不過這和三分法求極值相比有優勢嗎?


//
//  main.cpp
//  一元三次方程
//
//  Created by Candy on 2016/12/10.
//  Copyright © 2016年 Candy. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps=1e-3;
double a,b,c,d;
inline double f(double x){return ((a*x+b)*x+c)*x+d;}
inline double df(double x){return (3*a*x+2*b)*x+c;}
double sol(double l,double r){//printf("sol %lf %lf\n",l,r);
    int step=20;double x=(l+r)/2;
    while(step--){
        x=x-f(x)/df(x);
    }
    return x;
}
int main(int argc, const char * argv[]) {
    scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
    double p1=(-sqrt(b*b-3*a*c)-b)/(3*a),
    p2=(+sqrt(b*b-3*a*c)-b)/(3*a);
    printf("%.2f %.2f %.2f\n",sol(-100,p1),sol(p1,p2),sol(p2,100));
    return 0;
}

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM