1. 程式人生 > >【數學】三分法

【數學】三分法

Definition

當一個函式\(f(x)\)滿足在區間在區間\([l,r]\)內有且僅有一個\(x~\in~[l,r]~,~s.t.~~f(x)\)\([l,x]\)內單調嚴格遞增,在\([x,r]\)內單調嚴格遞減,則說\(f(x)\)\([l,r]\)內是一個單峰函式,求出單峰點\(x\)的演算法為三分法。

Solution

考慮對一個區間\([l,r]\),取三等分點,記做\(midl\)\(midr\)。不妨設\(midl~<~midr\),則若\(f(midl)~\leq~f(midr)\),則單峰點一定在區間\([midl,r]\)範圍內。反之單峰點一定在區間\([l,midr]\)

範圍內。

證明:

首先設\(f(midl)~<~f(midr)\)

以下說明\(midl\)一定不在單峰點右側。

\(midl\)在單峰點右側,則\(\forall~x_0~\in~(midl,r]\),都有\(f(x_0)~<~f(x)\)。因為\(midr~>~midl\)\(f(midr)~>~f(midl)\),於是產生矛盾。故可說明\(midl\)一定不再單峰點右側。

\(f(midl)~>~f(midr)\)時,證明同上。

再設\(f(midl)~=~f(midr)\)

以下說明單峰點一定在\([midl,midr]\)之間

假設\(midl\)

\(midr\)同在單峰點一側,則\(f(x)\)在區間\([midl,midr]\)上嚴格單調,而\(f(midl)~=~f(midr)\),產生矛盾。於是單峰點一定在\([midl,midr]\)之間。

證畢

於是在\([l,r]\)內取兩個三等分點(在程式碼中使用黃金分割點),比較兩點函式值大小,對函式值較小的一側縮小區間即可。

Example

傳送門

Description

給出一個\(N\)次函式,保證在範圍\([l,r]\)記憶體在一點\(x\),使得\([l,x]\)上單調增,\([x,r]\)上單調減。試求出\(x\)的值。

Input

第一行一次包含一個正整數N和兩個實數\(l,r\)

,含義如題目描述所示。

第二行包含\(N+1\)個實數,從高到低依次表示該\(N\)次函式各項的係數。

Output

輸出為一行,包含一個實數,即為\(x\)的值。四捨五入保留5位小數。

Hintt

\(forall:\)

\(7~\leq~n~\leq~13~,~|A_i|~<10\)。其中\(|A_i|\)為係數

Solution

板子題要啥solution

Code

#include<cmath>
#include<cstdio>
#define rg register
#define ci const int
#define cl const long long

typedef long double ldb;
typedef long long int ll;

template <typename T>
inline void qr(T &x) {
    rg char ch=getchar(),lst=' ';
    while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();
    while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(lst == '-') x=-x;
}

namespace IO {
    char buf[120];
}

template <typename T>
inline void qw(T x,const char aft,const bool pt) {
    if(x < 0) {x=-x,putchar('-');}
    rg int top=0;
    do {IO::buf[++top]=x%10+'0';} while(x/=10);
    while(top) putchar(IO::buf[top--]);
    if(pt) putchar(aft);
}

inline void readldb(long double &x) {
    double _temp;
    scanf("%lf",&_temp);
    x=_temp;
}

inline void printldb(const long double &x) {
    double _ret=x;
    printf("%.5lf\n",_ret);
}

const int maxn = 20;
const long double eps = 1e-10l;
const long double mul = 0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374l;

int n;
ldb MU[maxn];

ldb ask(ldb);

int main() {
    qr(n);
    ldb l,r;readldb(l);readldb(r);
    for(rg int i=0;i<=n;++i) readldb(MU[i]);
    while((r-l) >= eps) {
        ldb midl=r-(r-l)*mul,midr=l+(r-l)*mul;
        ldb ansl=ask(midl),ansr=ask(midr);
        if(ansl >= ansr) r=midr-eps;
        else l=midl+eps;
    }
    printldb(l);
    return 0;
}

ldb ask(ldb x) {
    ldb _ret=0,_dx=1;
    for(rg int i=n;~i;--i) _ret+=MU[i]*_dx,_dx*=x;
    return _ret;
}

Summary

當且僅當在單峰點兩側嚴格單調才能作為單峰函式處理