1435.【例题3】曲线

信息学奥赛一本通 二分查找

【题目描述】

明明做作业的时候遇到了nn个二次函数Si(x)=ax2+bx+c,他突发奇想设计了一个新的函数F(x)=max(Si(x)), i=1,2...n。

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

【输入】

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

【输出】

每组数据一个输出,表示新函数F(x)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;

前50%数据,n≤100。

【分析】

如果a>0,则函数图像是开口向上的抛物线,有最低值。如果a==0,则函数图像是一条直线,也有最低值。所以选择x由两端0,1000向中间逼近,x1,x2分别取值,最终x1==x2时,得到最低值。

l_mid = left + (right - left)/3;//左边取值 1/3
r_mid = right - (right - left)/3;//右边取值 1/3

在进行查找时,根据函数值结果来更新left、right。

y1 = calc(l_mid);//左边函数值
y2 = calc(r_mid);//右边函数值
/*
y1 < y2,说明最低点在左边,更新right
y1 == y2,说明最低点在l_mid与r_mid中间,更新left或right
y1 > y2,说明最低点在右边,更新left
*/
if(y1 <= y2){
	right = r_mid;
	}else{
	left = l_mid;
	}

【完整代码】

#include <bits/stdc++.h>

using namespace std;
struct Node{
	int a,b,c;
}s[10005];
int n;
double calc(double x){
	double ans = -1e9;
	//n行参数,选函数值最大的
	for(int i = 0; i < n; i++){
		ans = max(ans, s[i].a*x*x + s[i].b*x + s[i].c);
	}
	return ans;
}
int main(int argc, char *argv[]) {
	int t;
	cin >> t;
	for(int i = 0; i < t; i++){//t组
		cin >> n;
		for(int j = 0; j < n; j++){
			cin >> s[j].a >> s[j].b >> s[j].c;
		}
		double left = 0, right = 1000;
		double l_mid, r_mid, y1, y2;
		//二分查找,方程的抛物线上有两个x,由两边0~1000分别向中间进行计算
		while(fabs(right - left) > 1e-9){
			l_mid = left + (right - left)/3;//左边取值 1/3
			r_mid = right - (right - left)/3;//右边取值 1/3
			y1 = calc(l_mid);//左边函数值
			y2 = calc(r_mid);//右边函数值
			/*
			y1 < y2,说明最低点在左边,更新right
			y1 == y2,说明最低点在l_mid与r_mid中间,更新left或right
			y1 > y2,说明最低点在右边,更新left
			*/
			if(y1 <= y2){
				right = r_mid;
			}else{
				left = l_mid;
			}
		}
		//输出,最低点时y1==y2,输出y2也可以
		cout << fixed <<setprecision(4) << y1 << endl;
	}
	return 0;
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值