一本通题解——1435 曲线

题目链接

一本通:http://ybt.ssoier.cn:8088/problem_show.php?pid=1435

自己OJ:http://47.110.135.197/problem.php?id=4460

题目

题目描述

明明做作业的时候遇到了 n 个二次函数 S_{i}(x)=ax^{2}+bx+c,他突发奇想设计了一个新的函数F(x)=max(S_{i}(x)), i=1, 2, \cdots ,n


明明现在想求这个函数在 [0,1000] 的最小值,要求精确到小数点后四位四舍五入。

输入

输入包含T 组数据 (T < 10) ,每组第一行一个整数 n(n ≤ 10000) ,之后n行,每行3个整数a (0 ≤ a ≤ 100), b (|b| ≤ 5000), c (|c| ≤ 5000) ,用来表示每个二次函数的3个系数,注意二次函数有可能退化成一次。

输出

每组数据一个输出,表示新函数 F(x) 的在区间 [0,1000] 上的最小值。精确到小数点后四位,四舍五入。

样例输入

2
1
2 0 0
2
2 0 0
2 -4 2

样例输出

0.0000
0.5000

数据范围

T < 10,n ≤ 10000,0 ≤ a ≤ 100,|b| ≤ 5000, |c| ≤ 5000

分析

题意分析

提供了 n 个二次函数 S_{i}(x)=ax^{2}+bx+c,将这 n 函数构造成一个组合函数G(x)=\left\{\begin{matrix}a_1*x^{2}+b_1*x+c_1 \\ a_2*x^{2}+b_2*x+c_2 \\ \cdots \\ a_n*x^{2}+b_n*x+c_n \end{matrix}\right. ,然后求 max(G(x)) 在 [0, 1000] 这个区间的最小值。下面来分析样例数据,样例输入如上。

第一组输入,我们知道 n=1,对应的 a_{1}=2, b_{1}=0, c_{1}=0,那么 G(x)=2*x^{2},求 max(G(x))=max(2*x^{2}) 在区间 [0, 1000] 的最小值,自然我们知道最小值是当 x=0 的时候,对应的最小值为 0.0000。

第二组输入,我们知道 n=2,对应的 \begin{matrix}a_{1}=2,b_{1}=0,c_{1}=0 \\ a_{2}=2,b_{2}=-4,c_{2}=2 \end{matrix},那么对应的 G(x)=\left\{\begin{matrix}2*x^{2} \\ 2*x^{2}-4*x+2 \end{matrix}\right.,求 max(G(x)) 在区间 [0, 1000] 的最小值。最小值出现在当 x = 0.5 的时候,G_{1}(x)=2*0.5*0.5=0.5\\G_{2}(x)=2*0.5*0.5-4*0.5+2=0.5 ,对应的最小值为 0.5000。

算法思路

一题典型的浮点数二分查找。

二分查找

1、在 left=0,right=1000 这个范围进行三分查找。

2、只要左边界和右边界之间差值大于某个精度,即 fabs(right - left) > eps ,进行三分查找。

3、计算右中间值(r_mid),使用右中间值计算出 max(G(x)),记为 ans_r。

4、计算左中间值(l_mid),使用左中间值计算出 max(G(x)),记为 ans_l。

5、比较 ans_r 和 ans_l 关系。当 ans_l \leqslant ans_r 时,移动右边界 right=r_mid;否则移动左边界 left=l_mid。

AC参考代码

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1e4;
int a[MAXN];//系数a数组
int b[MAXN];//系数b数组
int c[MAXN];//系数c数组

//计算max(s(x))
double calc(double x, int n) {
    double ans = -1e9;
    for (int i=0; i<n; i++) {
        ans = max(ans, a[i]*x*x+b[i]*x+c[i]);
    }
    return ans;
}

int main() {
    int t;
    cin >> t;

    int i, j;
    for (i=0; i<t; i++) {
        int n;
        cin >> n;

        for (j=0; j<n; j++) {
            cin >> a[j] >> b[j] >> c[j];
        }

        //使用三分
        double left = 0;
        double right = 1000;
        double l_mid;
        double ans1;
        double r_mid;
        double ans2;
        double eps = 1e-9;//精度
        while (fabs(right-left)>eps) {
            l_mid = left+(right-left)/3;
            r_mid = right-(right-left)/3;

            ans1 = calc(l_mid,n);
            ans2 = calc(r_mid,n);
            if (ans1<=ans2) {
                right = r_mid;
            } else {
                left = l_mid;
            }
        }
        printf("%.4lf\n", ans1);
    }

    return 0;
}

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值