1. 程式人生 > >P3382 【模板】三分法

P3382 【模板】三分法

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 【模板】三分法