• 【HDU4498】Function Curve-分段+自适应Simpson积分法


    测试地址:Function Curve
    题目大意:给定n(1n50)(ki,ai,bi),要求函数曲线:

    min(100,min{ki(xai)2+bi|0<in})

    x=0x=100所截出的长度。
    做法:这一题需要用到自适应Simpson积分法+分段。
    我们知道,当两个函数曲线之间存在交点时,那么当经过这个交点时,确定最小值的函数可能变化,而不经过交点时确定最小值的函数则不会变化,这启发我们将函数分段来求。
    首先把所有函数化成y=Ax2+Bx+C的形式(除了给出的n个函数外,还有一个y=100),我们发现n很小,所以我们暴力求出函数两两之间的交点(只需求出横坐标,用二次函数求根公式即可),然后将这些交点排序,那么相邻的两个交点之间就是一段了。这时候要注意,如果一个交点横坐标小于0或者大于100,就将它舍弃。然后对于每一段,找到这一段中确定最小值的函数(只需要把中点带进去,找到最小值所在的函数即可),然后就可以计算这个函数曲线在这一段上的长度了。
    关于计算函数曲线y=f(x)在区间[a,b]上的长度,有这样一个公式:
    len=ba1+f(x)2dx

    其中f(x)f(x)的导数。
    那么显然Ax2+Bx+C的导数是2Ax+B,将这个值带进去就可以用自适应Simpson积分法来计算定积分了。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    #define epss 1e-6
    using namespace std;
    int T,n,tot;
    double a[60],b[60],c[60],p[5010];
    double A,B,ans;
    
    bool cmp(double a,double b)
    {
      return a<b;
    }
    
    void solve(double A,double B,double C,double &x1,double &x2)
    {
      if (A==0&&B==0) {x1=x2=-1;return;}
      if (A==0) {x1=-C/B;x2=-1;return;}
      double delta=B*B-4*A*C;
      if (delta>=0)
      {
        x1=(-B+sqrt(delta))/(2*A);
        x2=(-B-sqrt(delta))/(2*A);
        if (fabs(x1-x2)<epss) x2=-1;
      }
      else x1=x2=-1;
    }
    
    double f(double x)
    {
      return sqrt(1+(2*A*x+B)*(2*A*x+B));
    }
    
    double calc(double a,double b)
    {
      double mid=(a+b)/2;
      return (b-a)/6*(f(a)+f(b)+4*f(mid));
    }
    
    double simpson(double a,double b,double eps)
    {
      double mid=(a+b)/2,s1=calc(a,b),s2=calc(a,mid),s3=calc(mid,b);
      if (fabs(s1-s2-s3)<=15*eps) return s2+s3+(s1-s2-s3)/15;
      else return simpson(a,mid,eps/2)+simpson(mid,b,eps/2);
    }
    
    int main()
    {
      scanf("%d",&T);
      while(T--)
      {
        scanf("%d",&n);
        a[0]=0,b[0]=0,c[0]=100;
        for(int i=1;i<=n;i++)
        {
          double k,x,y;
          scanf("%lf%lf%lf",&k,&x,&y);
          a[i]=k;
          b[i]=-2*k*x;
          c[i]=k*x*x+y;
        }
    
        tot=2;
        p[1]=0,p[2]=100;
        for(int i=0;i<=n;i++)
          for(int j=i+1;j<=n;j++)
          {
            double x1,x2;
            solve(a[i]-a[j],b[i]-b[j],c[i]-c[j],x1,x2);
            if (x1>=0) p[++tot]=x1;
            if (x2>=0) p[++tot]=x2;
          }
    
        sort(p+1,p+tot+1,cmp);
        ans=0;
        for(int i=1;i<tot;i++)
        {
          double l=p[i],r=p[i+1],mid=(l+r)/2,Min=1000;
          int mini;
          if (r>100.0) break;
          for(int j=0;j<=n;j++)
            if (a[j]*mid*mid+b[j]*mid+c[j]<Min)
            {
              Min=a[j]*mid*mid+b[j]*mid+c[j];
              mini=j;
            }
          A=a[mini],B=b[mini];
          ans+=simpson(l,r,epss);
        }
    
        printf("%.2lf
    ",ans);
      }
    
      return 0;
    }
    
  • 相关阅读:
    MyBatis通过Mapper动态代理来实现curd操作
    通过Mybatis原始Dao来实现curd操作
    MyBatis最原始的实现curd的操作
    通过重写request.getParameter方法来解决中文乱码问题。
    第九章:Servlet工作原理解析
    简述servlet
    Java中几个常用并发队列比较 | Baeldung
    记录java程序一次CPU占用90%问题排查过程
    日志查看
    mongo
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793622.html
Copyright © 2020-2023  润新知