what is 三分法

对于二分,相信你一定十分熟悉。就是在一个具有单调性序列上查找你所需要的数字。由于其单调性,你每一次在查找是就可以将规模缩小一半,大致就是:
1.假设这个数列单调递增
2.维护一个区间左端点ll,区间右端点r和中间点midmid
3.如果midmid比想要的值小,则左边肯定不可以,那么l=midl=mid
2.如果midmid比想要的值大,则右边肯定不可以,那么r=midr=mid
因此大致就可以这么写:

while (l+1<r)
{
    int mid=l+r>>1;
    if (v<a[mid) r=mid;
    else l=mid;
}

不保证代码正确,但是具体思想就是这样。
三分也一样啊:
对于一段抛物线(极值的一边单调递增,极值的一边单调递减)我们就可以把它分成三段,根据其图像特性来求解。


三分法求二次函数峰值

对于三分,我们用左端点lmidlmidrmidrmid进行维护,将这个图像分成三段。并且图像区间的左右端点分别是l&lt;r.l&lt;r.则我们可以选择这么考虑:(以二次函数y=5x2+8x1y=-5x^{2}+8x-1为例)
如图所示:
三分法求极值
lmidlmid处于AA点,rmidrmid处于BB点时:可将左端点ll缩到lmidlmid,右端点不变以保证极值存在。
lmidlmid处于AA点,rmidrmid处于CC点时:照样可以将ll缩到lmidlmid
同理,
lmidlmid处于CC点,rmidrmid处于DD点时:可将右端点rr缩到rmidrmid,左端点不变以保证极值存在。
lmidlmid处于BB点,rmidrmid处于BB点时:照样可以将rr缩到rmidrmid
故得到结论:
f(l)&lt;f(r)l=lmidf(l)&lt;f(r)→l=lmid
f(l)f(r)r=rmidf(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&lt;0a&lt;0的情况,不难得出:
f(l)f(r)l=lmidf(l)>f(r)→l=lmid
f(l)f(r)r=rmidf(l)≤f(r)→r=rmid
代码实现只要if内反一下即可:

#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内稍作修改即可。

相关文章:

  • 2021-12-17
  • 2021-08-31
  • 2021-11-23
  • 2021-10-29
  • 2022-12-23
  • 2021-06-16
  • 2022-12-23
猜你喜欢
  • 2021-09-06
  • 2022-01-23
  • 2022-12-23
  • 2021-05-03
  • 2021-09-30
相关资源
相似解决方案