luogu【P1024 一元三次方程求解】题解

题目描述

有形如: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


看到大家没人打通解,那么我来发一波~~~

蒟蒻的凝视~~~


可以先看一下此题的强化版:解方程 求解一个K次函数,那么我们只需从函数图像的各个顶点二分搜索一下就可以了。 比如说如下函数:

 

我们只需在-∞到第一个顶点中搜索解,再在第一个顶点到第二个顶点中搜索……直到第n个顶点到∞中搜索解。

所以,我们只需找到此函数顶点的x值就可以了。方法很简单,只需求导,再解一下求导后的方程。

我们可以知道,对于一个

∑i=0->n aix^i = 0

的方程,n次求导后总会变成一次函数。之后再解方程,就可以一步一步把解给求出来。

代码比较奇怪,我打了一个class,希望对大家有用。

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
class fun{
private:
    int n;
    vector <double> num;
public:
    fun ()
    {
        n=0;
        num.clear();
    }
    int size()
    {
        return n;
    }

    vector <double> getarray()
    {
        return num;
    }

    void insert(vector <double> p)
    {
        num=p;
        n=p.size();
    }

    void mem(int p,double e,...)
    {
        double *q=&e;
        n=p;
        for (int i=1;i<=n;i++)
        {
            num.pb(*q);
            q++;
        }
    }

    double operator ()(double x)
    {
        double ans=0;
        double xt =1;
        for (int i=0;i<=n-1;i++)
        {
            ans+=xt*num[i];
            xt*=x;
        }
        return ans;
    }

    void print()
    {
        for (int i=0;i<n;i++)
        {
            if (i==0) cout << num[i];
            else
            if (num[i] != 0)
            {
                if (num[i]<0)
                    cout << num[i] << "x^"<<i;
                else cout << "+" << num[i] << "x^"<<i;
            }
        }
    }
    fun operator !()
    {
        fun H;
        H.n=n-1;
        for (int i=0;i<H.n;i++)
        {
            H.num.pb((i+1)*num[i+1]);
        }
        return H;
    }

    double get_root(double p,double q)
    {
        fun f;
        f.insert(num);
        if (f(p)*f(q)>0) return -100000000;
        double mid = (p+q)2;
        while (p+0.000001<q)
        {
            if (f(p)*f(mid)<=0) q=mid;
            else p=mid;
            mid=(p+q)2;
        }
        return mid;
    }

    double operator [] (int p)
    {
        return num[p];
    }
};

vector <double> get_all_answer(double s,double e,fun f)
{
    vector <double> ret;
    vector <double> qw;
    qw = f.getarray();
    ret.clear();
    if (qw.size()<=2)
    {
        ret.pb(-qw[0]qw[1]);
        return ret;
    }
    vector <double> ans_list = get_all_answer(s,e,(!f));
    if (ans_list.size()==0)
    {
        if (f.get_root(s,e)>-99999999) ret.pb(f.get_root(s,e));
        return ret;
    }
    if (f.get_root(s,ans_list[0])>-99999999) ret.pb(f.get_root(s,ans_list[0]));
    for (int i=0;i<ans_list.size()-1;i++)
    {
        if (f.get_root(ans_list[i],ans_list[i+1])>-99999999)
            ret.pb(f.get_root(ans_list[i],ans_list[i+1]));
    }
    if (f.get_root(ans_list[ans_list.size()-1],e)>-99999999)
        ret.pb(f.get_root(ans_list[ans_list.size()-1],e));
    vector <double> RET;
    if (ret.size()==0) return ret;
    RET.pb(ret[0]);
    for (int i=1;i<ret.size();i++)
    {
        if (abs(ret[i]-ret[i-1])>0.00001)
            RET.pb(ret[i]);
    }
    return RET;
}

int main()
{
    fun f;
    vector <double> g;
    int n;
    cin >> n;
    n++;
    for (int i=1;i<=n;i++)
    {
        double x;
        cin >> x;
        g.pb(x);
    }
    f.insert(g);
    double s,e;
    cin >> s >> e;
    vector <double> ans;
    ans = get_all_answer(s,e,f);
    for (int i=0;i<ans.size();i++)
        printf("%.5lf ",ans[i]);
}

原文地址:https://www.cnblogs.com/dgklr/p/9077553.html