三分法求單峯(單谷)函數極值

<font size=4> ## what is 三分法 對於二分,相信你必定十分熟悉。就是在一個具備單調性序列上查找你所須要的數字。因爲其單調性,你每一次在查找是就能夠將規模縮小一半,大體就是: 1.假設這個數列單調遞增 2.維護一個區間左端點$l$,區間右端點r和中間點$mid$ 3.若是$mid$比想要的值小,則左邊確定不能夠,那麼$l=mid$ 2.若是$mid$比想要的值大,則右邊確定不能夠,那麼$r=mid$ 所以大體就能夠這麼寫: ``` while (l+1<r) { int mid=l+r>>1; if (v<a[mid) r=mid; else l=mid; } ``` 不保證代碼正確,可是具體思想就是這樣。 三分也同樣啊: 對於一段拋物線(極值的一邊單調遞增,極值的一邊單調遞減)咱們就能夠把它分紅三段,根據其圖像特性來求解。c++


三分法求二次函數峯值

對於三分,咱們用左端點$lmid$和$rmid$進行維護,將這個圖像分紅三段。而且圖像區間的左右端點分別是$l<r.$則咱們能夠選擇這麼考慮:(以二次函數$y=-5x^{2}+8x-1$爲例) 如圖所示: 函數圖像 當$lmid$處於$A$點,$rmid$處於$B$點時:可將左端點$l$縮到$lmid$,右端點不變以保證極值存在。 當$lmid$處於$A$點,$rmid$處於$C$點時:照樣能夠將$l$縮到$lmid$。 同理, 當$lmid$處於$C$點,$rmid$處於$D$點時:可將右端點$r$縮到$rmid$,左端點不變以保證極值存在。 當$lmid$處於$B$點,$rmid$處於$B$點時:照樣能夠將$r$縮到$rmid$。 故獲得結論: $$f(l)<f(r)→l=lmid$$ $$f(l)≥f(r)→r=rmid$$ 而後就進行簡單的代碼實現:函數

#include<bits/stdc++.h>
using namespace std;
double a,b,c;
inline double f(double x) {
	return a*x*x+b*x+c;
}
int main(void)
{
	cin>>a>>b>>c;
	//形如y=ax^2+by+c的二次函數
	double l=-1e9,r=1e9;
	while (l+1e-9<r)
	{
		double lmid=l+(r-l)/3.0;
		//圖像上位於1/3部分的靠左的mid值 
		double rmid=l+(r-l)/3.0*2.0;
		//圖像上位於2/3部分的靠右的mid值
		if (f(lmid)<f(rmid)) l=lmid;
		else r=rmid;
		//求單峯極值 
	} 
	cout<<"X="<<l<<'\n';
	cout<<"Y="<<f(l); 
}

二次函數求單谷谷值 & 高次函數應用

經過畫圖和分類討論$a<0$的狀況,不可貴出: $$f(l)>f(r)→l=lmid$$ $$f(l)≤f(r)→r=rmid$$ 代碼實現只要if內反一下便可:spa

#include<bits/stdc++.h>
using namespace std;
double a,b,c;
inline double f(double x) {
	return a*x*x+b*x+c;
}
int main(void)
{
	cin>>a>>b>>c;
	//形如y=ax^2+by+c的二次函數
	double l=-1e9,r=1e9;
	while (l+1e-9<r)
	{
		double lmid=l+(r-l)/3.0;
		//圖像上位於1/3部分的靠左的mid值 
		double rmid=l+(r-l)/3.0*2.0;
		//圖像上位於2/3部分的靠右的mid值
		if (f(lmid)>f(rmid)) l=lmid;
		else r=rmid;
		//求單峯極值 
	} 
	cout<<"X="<<l<<'\n';
	cout<<"Y="<<f(l); 
}

若是須要高次函數過其它圖像,只要在f內稍做修改便可。code

相關文章
相關標籤/搜索