hdu4498Function Curve(数值积分)

先把所有曲线的交点(加上0.0和100.0)都找出来,排个序,然后相邻的两个节点用辛普森自适应积分求出,当然要先求出此时对应的最小值函数,只需要取这一段的中点m,求出哪条曲线使ki * (x - ai) * (x - ai) + bi最小(扫一遍),那么这一段对应的最小值函数就是这个曲线。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;

int A[55],B[55],k[55];
//simpson
int low;
#define mpow(X) ((X)*(X))
double F(double x)
{return sqrt(1.0+mpow(2.0*k[low]*x+1.0*A[low])); }
double simpson(double a,double b)
{return (F(a)+4*F(a+(b-a)/2.0)+F(b))*(b-a)/6.0;}
double asr(double a,double b,double eps,double A)
{
    double c=a+(b-a)/2.0;
    double L=simpson(a,c),R=simpson(c,b);
    if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15.0;
    return asr(a,c,eps/2.0,L)+asr(c,b,eps/2.0,R);
}
vector<double> v;
typedef long long LL;
void push(double t)
{if(t>0.0&&t<100.0) v.push_back(t);}
void add(int a,int b,int c)
{
    if(a==0){
        if(b) push((double)c/(double)b);
        return;
    }
    LL delta=(LL)b*b-4ll*a*c;
    if(delta<0ll) return;
    if(delta==0ll) push(-(double)b/2.0/a);
    else    push((-(double)b+sqrt((double)delta))/2.0/a),
    push((-(double)b-sqrt((double)delta))/2.0/a);
}
int main(void)
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",k+i,A+i,B+i);
            B[i] = k[i]*A[i]*A[i]+B[i];
            A[i] = -2*k[i]*A[i];
        }   
        k[0]=A[0]=0,B[0]=100;//补充f0=100;
        v.clear();
        for(int i=0;i<n;i++)
            for(int j=i+1;j<=n;j++)
                add(k[i]-k[j],A[i]-A[j],B[i]-B[j]);
        v.push_back(0.0);
        v.push_back(100.0);
        sort(v.begin(),v.end());
        int sz=v.size();
        double curve=0,eps=1e-7;
        for(int i=0;i<sz-1;i++)
        {
            if(fabs(v[i+1]-v[i])<eps) continue;
            double mid=(v[i]+v[i+1])/2.0,lowval;
            low=0,lowval=k[low]*mid*mid+A[low]*mid+B[low];
            for(int j=1;j<=n;j++)
            {
                double tmp=k[j]*mid*mid+A[j]*mid+B[j];
                if(tmp<lowval) lowval=tmp,low=j;
            }
            curve+=asr(v[i],v[i+1],eps,simpson(v[i],v[i+1]));
        }
        printf("%.2f\n",curve );
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值