P3382 【模板】三分法
阿新 • • 發佈:2018-10-02
const tdi 好的 分法 pri cst max 。。 模擬退火
菜雞刷模板系列。。。
這道題其實是可以二分的,但是有更好的算法,叫做三分。
三分這種算法用於求單峰函數的最大值或者最小值。
算法思想就是弄\((l, r)\)區間的兩個三等分點,然後來縮小範圍。
因為這道題是求峰頂,所以我們可以模擬退火通過兩個三等分點的大小關系來縮小範圍。
我們把那個值小的那邊的範圍弄掉,慢慢我們就會到達峰頂。
還有另外一種也聽容易的做法:求導後二分導函數。這個沒什麽難度。
這道題的函數是個\(n\)次的函數,也就是個\(n\)次的多項式,我們可以用秦九韶算法來優化。
當然,模擬退火是真的可以做的。這個坑等以後來填。。。
\[a_nx^n+a_{n-1}x^{n-1}+a_{n-2}x^{n-2}+...+a_2x^2+a_1x+a_0=0\]
\[y‘=na_nx^{n-1}+(n-1)a_{n-1}x^{n-2}+(n-2)a_{n-2}x^{n-3}+...+2a_2x+a_1\]
代碼:
第一份:求導二分求零點的。
#include<cstdio> #include<cmath> const int maxn = 17; const double eps = 1e-6; int n; double l, r; double a[maxn]; double fd(double x) { double ans = n * a[n]; for(int i = n - 1; i >= 1; i--) { ans = ans * x + i * a[i]; } return ans; } int main() { scanf("%d%lf%lf", &n, &l, &r); for(int i = n; i >= 0; i--) scanf("%lf", &a[i]); while(l < r) { if(r - l < eps) break; double mid = (l + r) / 2; if(fd(mid) > 0) l = mid; else r = mid; } printf("%.5lf\n", l); return 0; }
第二份:三分法。
#include<cstdio> #include<cmath> const int maxn = 17; const double eps = 1e-6; int n; double l, r; double a[maxn]; double f(double x) { double ans = a[n]; for(int i = n - 1; i >= 0; i--) ans = ans * x + a[i]; return ans; } int main() { scanf("%d%lf%lf", &n, &l, &r); for(int i = n; i >= 0; i--) scanf("%lf", &a[i]); while(r - l >= eps) { double lm = l + (r - l) / 3, rm = r - (r - l) / 3; if(f(lm) > f(rm)) r = rm; else l = lm; } printf("%.5lf\n", l); return 0; }
P3382 【模板】三分法