zoukankan      html  css  js  c++  java
  • 一元三次方程求解(数学、二分)

    https://www.luogu.com.cn/problem/P1024

    Description

    有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。
    给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求三个实根。

    Input

    四个实数:a,b,c,d

    Output

    由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位

    Sample Input

    1 -5 -4 20

    Sample Output

    -2.00 2.00 5.00
     

    HINT

    数据规模和约定
    |a|,|b|,|c|,|d|<=10

    记方程f(x)=0,若存在2个数x1x2,且x1<x2f(x1)×f(x2)<0,则在(x1,x2)之间一定有一个根。

    这题解法比较多

    因为区间很大,所以可以二分。

    题目保证三个答案都在[-100,100]范围内,且两个根的差的绝对值>=1,所以每一个大小为1的区间里至多有1个解。

    当区间的两个端点的函数值异号时区间内一定有一个解,这个时候我们可以在区间内进行二分查找ans,如果同号则该区间一定没有解。

    刚开始遍历i从-10000到10000了,然后i再除以100当成x的值,没想到这样显示TLE了。。。

     1 #include <stdio.h>
     2 #include <iostream>
     3 #include <string>
     4 #include <string.h>
     5 #include <algorithm>
     6 #include <map>
     7 #include <vector>
     8 #include <set>
     9 #include <stack>
    10 #include <queue>
    11 #include <math.h>
    12 #include <sstream>
    13 using namespace std;
    14 typedef long long LL;
    15 const int INF=0x3f3f3f3f;
    16 const int maxn=1e5+10;
    17 const double eps = 1e-8;
    18 const double PI = acos(-1);
    19 
    20 double a,b,c,d;//开成double吧,免得出错 
    21 vector<double> ans;
    22 double f(double x)
    23 {
    24     return a*x*x*x+b*x*x+c*x+d;
    25 }
    26 
    27 double solve(double x1,double x2)    //在x1和x2中二分找答案 
    28 {
    29     double L=x1,R=x2;
    30     while(R-L>1e-4)    //这里的eps一般要比题中要求的精度(1e-2)多两位。
    31     {
    32         double mid=(L+R)/2;
    33         double t1=f(L);
    34         double t2=f(mid);
    35         double t3=f(R);
    36         if(t2==0) return mid;
    37         if(t1*t2<0) R=mid;
    38         else if(t2*t3<0) L=mid;
    39     }
    40     return (L+R)/2;//返回L,R,(L+R)/2都行
    41 }
    42 
    43 int main()
    44 {
    45     #ifdef DEBUG 
    46     freopen("sample.txt","r",stdin);
    47     #endif
    48     
    49     scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
    50     double pre=f(-100.0);
    51     for(int i=-100;i<=100;i++)
    52     {
    53         double t=f(i);
    54         if(t!=0)
    55         {
    56             if(t*pre<0) ans.push_back(solve(i-1,i));
    57         }
    58         else ans.push_back(i);
    59         pre=t;
    60     }
    61     for(int i=0;i<3;i++)
    62         printf(i==2?"%.2f
    ":"%.2f ",ans[i]);
    63     
    64     return 0;
    65 }

    下面是我看别的大佬写的

    盛金公式:

     

     1 #include <iostream>
     2 #include <math.h>
     3 #include <iomanip>
     4 using namespace std;
     5 int main()
     6 {
     7      double a,b,c,d;
     8      double as,bs,t,si;
     9      double x1,x2,x3;
    10      cin>>a>>b>>c>>d;
    11      as=b*b-3*a*c;
    12      bs=b*c-9*a*d;
    13      t=(2*as*b-3*a*bs)/(2*sqrt(as*as*as));
    14      si=acos(t);
    15      x1=(-b-2*sqrt(as)*cos(si/3))/(3*a);
    16      x2=(-b+sqrt(as)*(cos(si/3)+sqrt(3)*sin(si/3)))/(3*a);
    17      x3=(-b+sqrt(as)*(cos(si/3)-sqrt(3)*sin(si/3)))/(3*a);
    18      cout<<fixed<<setprecision(2)<<x1<<" ";
    19      cout<<fixed<<setprecision(2)<<x3<<" ";
    20      cout<<fixed<<setprecision(2)<<x2<<" ";
    21      return 0;
    22 }

    最后是EarthGiao大佬写的题解:

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

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

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

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

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

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

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

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #define eps 1e-4
     5 using namespace std;
     6 double x1,x2,x3,a,b,c,d;
     7 double f(double x){return a*x*x*x+b*x*x+c*x+d;}
     8 double df(double x){return 3*a*x*x+2*b*x+c;}
     9 double slove(double l,double r)
    10 {
    11     double x,x0=(l+r)/2;
    12     while(abs(x0-x)>eps)
    13       x=x0-f(x0)/df(x0),swap(x0,x);
    14     return x;
    15 }
    16 int main()
    17 {
    18     cin>>a>>b>>c>>d;
    19     double p=(-b-sqrt(b*b-3*a*c))/(3*a);
    20     double q=(-b+sqrt(b*b-3*a*c))/(3*a);
    21     x1=slove(-100,p),x2=slove(p,q),x3=slove(q,100);
    22     printf("%.2lf %.2lf %.2lf",x1,x2,x3);
    23     return 0;
    24 }

    -

  • 相关阅读:
    HttpEntity转换Inputstream(红色)加XmlPull解析
    ImageLoader加载图片
    HttpClient——Get,Post
    Android例子源码非第三方实现根据字母排序的城市列表
    Android 仿QQ消息界面
    css折叠表格
    前端页面文字长度显示控制
    (首页上一页下一页尾页 + 下拉框跳转)分页功能
    基于bootstrap的分页插件
    HTML 禁止复制文字
  • 原文地址:https://www.cnblogs.com/jiamian/p/12388066.html
Copyright © 2011-2022 走看看