三分算法(秦九韶算法补充)

本文深入探讨了三分法算法,一种高效寻找凸函数最值的方法。对比二分法,三分法适用于非单调但具备凸凹特性的函数。文章通过一道经典问题引入三分法的应用场景,详细解析了算法实现步骤,并提供了代码示例。适合算法初学者和进阶者学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

介绍:

问题引入:

补充:秦九韶算法

解法:

三分

思路:(以上凸函数为例,下凸函数反之)

代码:

一、函数为上凸函数

二、函数为下凸函数

模板题:


介绍:

说起三分,肯定要提到三分的近亲——二分。

回顾一下二分是什么:对于一个区间,求得其目标(可以是最值),我们可以采取折半查找,若一边的条件不满足,则继续向另外一边折半下去,直到l==r(有些时候有误差),此时的mid即为所求。这样的算法时间复杂度是log量级的。

而三分算法的话,时间复杂度也是log量级的,具体的话好像是O(log3^n)(省略常数)

其做法是:将给定的区间平均分成3段,比较这三段端点的值,然后与二分一样查找,直到找到为止

那么,三分与二分有什么不同呢?

二分法适用于一个单调序列,请注意,一定是单调!!!

三分法则适用于一个凸函数(上凸与下凸,就是二次函数基本形式中的a<0,a>0的情况)

 

问题引入:

(luogu P3382)

题目描述

如题,给出一个N次函数,保证在范围[l,r]内存在一点x,使得[l,x]上单调增,[x,r]上单调减。试求出x的值。

输入格式

第一行一次包含一个正整数N和两个实数l、r,含义如题目描述所示。

第二行包含N+1个实数,从高到低依次表示该N次函数各项的系数。

输出格式

输出为一行,包含一个实数,即为x的值。四舍五入保留5位小数。

输入输出样例

输入 #1

3 -0.9981 0.5
1 -3 -3 1

输出 #1

-0.41421

说明/提示

时空限制:50ms,128M

数据规模:

对于100%的数据:7<=N<=13

样例说明:

如图所示,红色段即为该函数f(x)=x^3-3x^2-3x+1在区间[-0.9981,0.5]上的图像。

当x=-0.41421时图像位于最高点,故此时函数在[l,x]上单调增,[x,r]上单调减,故x=-0.41421,输出-0.41421。

(Tip.l&r的范围并不是非常大ww不会超过一位数)

 

补充:秦九韶算法

在本题中设计一个函数的计算:

首先,拿到这个函数,学过因式分解的蒻蒻都会将x每一项都提出来,我们是否可以试试看?

那么f(x)就是如下形式:

……

然后就会发现一个递推关系:

int f(int x)
{
    int F=0;
    for(int i=n;i>=0;i--)
	F=F*x+a[i];
    return F;
}

但是这道题就是需要用double类型,更改一下就好了

 

解法:

暴力

这个从区间l~r开始枚举,请记住,循环变量i的数据类型是double型!!!

套用秦九韶算法求得函数的值,然后发现f(x+1)<f(x)的时候,输出x即可

三分

本道题目我们用一个更加智慧的办法:三分法,将这个函数均匀分成三段,然后不断更新区间,就可以查到最值(的横坐标)

 

三分

思路:(以上凸函数为例,下凸函数反之)

既然是分成三段,那么根据植树问题,l,r之间必然有两个点(lmid、rmid),并且这两个点之间的间距等于靠左的点到l的间距,等于靠右的点到r的间距。那么,就可以给这两个点赋值:

k=(r-l)/3;

lmid=l+k;rmid=r-k;

接着就是判定条件:

根据函数的单调性,在这个上凸函数上,在极值点左边的必然是单调递增,右边的反之。

所以说,如果f(lmid)>f(rmid)的话,那么说明lmid离极值点比较近,就需要我们把右边的r向上移动至原来rmid的位置

否则,反之。

这里的否则包含了f(lmid)==f(rmid)的情况,那就是极值点在正中间,我觉得可以直接输出(输出的时候要注意比较mid和mid+1的函数值,mid=(lmid+rmid)/2)了。

但是有很多dalao没有这么写,如果继续跑下去的话也没有大问题,我们还是学一下dalao们吧,因为撞到lmid==rmid的概率很小

下面,就直接贴代码吧

 

代码:

一、函数为上凸函数

int型:

int three(int l,int r)
{
	while(r-l>=1)//一个很小的数,请根据题目设定
	{
		int k=(r-l)/3;
		int lmid=l+k,rmid=r-k;
		if(f(lmid) > f(rmid))
			r=rmid;
		else
			l=lmid;
	}
	return f(l)>f(l+r/2) ? l : (l+r)/2;//比较可能有误差
}

double型:

double three(double l,double r)
{
	while(r-l>=0.0000001)//一个很小的数,请根据题目设定
	{
		double k=(r-l)/3.0;
		double lmid=l+k,rmid=r-k;
		if(f(lmid) > f(rmid))
			r=rmid;
		else
			l=lmid;
	}
	return f(l)>f(l+r/2) ? l : (l+r)/2;//比较可能有误差
}

二、函数为下凸函数

int型:

int three(int l,int r)
{
	while(r-l>=1)//一个很小的数,请根据题目设定
	{
		int k=(r-l)/3;
		int lmid=l+k,rmid=r-k;
		if(f(lmid) > f(rmid))
			r=rmid;
		else
			l=lmid;
	}
	return f(l)>f(l+r/2) ? l : (l+r)/2;//比较可能有误差
}

double型:

double three(double l,double r)
{
	while(r-l>=0.0000001)//一个很小的数,请根据题目设定
	{
		double k=(r-l)/3.0;
		double lmid=l+k,rmid=r-k;
		if(f(lmid) < f(rmid))
			r=rmid;
		else
			l=lmid;
	}
	return f(l)>f(l+r/2) ? l : (l+r)/2;//比较可能有误差
}

注:本蒟蒻没有试验过int型的正确性,而且三分的题目大多都是double型的……

若真的出现int的三分,还请读者试验一下,不可尽信,也不可不信……

 

模板题:

luogu 3382

POJ 3737

POJ3301

 

 

希望能帮助到你!欢迎dalao提出问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值