#LOJ10013 曲線(三分)
阿新 • • 發佈:2018-12-15
題目描述
明明做作業的時候遇到了 n 個二次函式 Si(x)=ax^2 + bx + c,他突發奇想設計了一個新的函式 F(x)=max{Si(x)},i=1…n。
明明現在想求這個函式在 [0,1000] 的最小值,要求精確到小數點後四位,四捨五入。
輸入格式
輸入包含 T 組資料,每組第一行一個整數n;
接下來 n 行,每行 3 個整數 a, b, c ,用來表示每個二次函式的 3 個係數。注意:二次函式有可能退化成一次。
輸出格式
每組資料輸出一行,表示新函式 F(x) 的在區間 [0,1000] 上的最小值。精確到小數點後四位,四捨五入。
樣例
樣例輸入
2 1 2 0 0 2 2 0 0 2 -4 2
樣例輸出
0.0000
0.5000
資料範圍與提示
對於 50% 的資料,1≤n≤100;
對於 100% 的資料,1≤T≤10, 1≤n≤10^5, 0≤a≤100, 0≤∣b∣≤5000, 0≤∣c∣≤5000。
三分法適用於求解凸性函式的極值問題,二次函式就是一個典型的單峰函式。
設當前求解的區間為[l,r],令,,接著計算這兩個點的函式值,之後將兩點中函式值更優的那個點稱為“好點”(若計算最小值,則f更小的那個點就為好點),而函式值較差的那個點稱為“壞點”。
可以利用反證法證明:最優點和好點在壞點的同側。
如圖,f(m2)>f(m1),最大值為最優點,因此m1是壞點,m2是好點,最優點與m2會位於m1同側,求解區間由[l,r]變為[m1,r]。由此可以不停縮小求解區間,直至得出近似解。
如果函式不嚴格單調,三分法將不適用。
由於a大於等於0,函式S是開口向上的二次函式(當a=0時是一次函式),即S為先單調遞減,後單調遞增的下凸函式,或者是一次單調函式,F(x)=max{Si(x)}也滿足單調性。因此可用三分法求解[0,1000]內的最小值。
AC程式碼:
////CSDN部落格:https://blog.csdn.net/qq_40889820 #include<iostream> #include<sstream> #include<algorithm> #include<string> #include<cstring> #include<iomanip> #include<vector> #include<cmath> #include<ctime> #include<stack> #include<queue> #include<map> #define mem(a,b) memset(a,b,sizeof(a)) #define e 2.71828182 #define Pi 3.141592654 #define INF 1<<30 using namespace std; struct node { double a,b,c; }quad[10010]; int n; double fun(double x)//F(x) { double ans=-INF; for(int i=1;i<=n;i++) ans=max(ans,quad[i].a*x*x+quad[i].b*x+quad[i].c); return ans; } int main() { ios::sync_with_stdio(false); cin.tie(NULL);cout.tie(NULL); int T; cin>>T; while(T--) { cin>>n; for(int i=1;i<=n;i++) cin>>quad[i].a>>quad[i].b>>quad[i].c; double l=0.0,r=1000.0;//[0,1000] while(r-l>1e-11) { double mid1=l+(r-l)/3,mid2=r-(r-l)/3; if(fun(mid1)<fun(mid2))//mid1是好點 r=mid2; else l=mid1; } cout<<setiosflags(ios::fixed)<<setprecision(4)<<fun(l)<<endl; } }