1435:【例題3】曲線
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 982 通過數: 504
【題目描述】
明明做作業的時候遇到了n個二次函數Si(x)=ax2+bx+c,他突發奇想設計了一個新的函數F(x)=max(Si(x)), i=1,2…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;
前50%數據,n≤100。
思路:
求區間[L,R],令m1 = l +( r-l)/3,m2=r-(r-l)/3接着計算函數值f(m1),f(m2)之後我們將兩點中函數值更優的那個點稱爲好點,差的那個點叫壞點。最優點會與好點與壞點同側。
f(m1)>f(m2),則m1是好點,m2是壞點。因此最優點會與m1在一起在m2的左側。即求區間[L,R]變成[L,m2].注意函數的嚴格單調性。
三分模板:
double l = 0,r = 1E9;
while(r - l >= 1e-3)//計算機中不存在真正的零值,所以用一個很小的值來代替零。
{
double m1 = l +( r-l)/3,m2 = r-(r-l)/3;
if(m1 < m2) l = m1;
else r = m2;
}
本題爲開口向上的二次函數,S的定義先單調遞減後單調遞增的的下凸函數。F(X)滿足單調性,選用三分法得出最小值。
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#define INF 0X3F3F3F3F
using namespace std;
int T,test,n;
double a[10005],b[10005],c[10005];
double x,maxx = 0,L,r,Lmid,rmid;
double cal(double x){
int i,j;
double maxx= -INF;
for(i = 1;i <= n;i++) maxx=max(maxx,a[i]*x*x+b[i]*x+c[i]);
return maxx;
}
int main(){
int i,j;
cin>>T;
for(test = 1;test <= T;test++){
cin>>n;
for(i = 1;i <= n;i++) cin>>a[i]>>b[i]>>c[i];
L = 0;r = 1000;
while(L+1e-11 < r){
Lmid = L + (r-L)/3;
rmid = r - (r-L)/3;
if(cal(Lmid) <= cal(rmid)) r = rmid;
else L = Lmid;
}
printf("%.4lf\n",cal(L));
}
return 0;
}