简介
本算法用来求解凸函数极值点的问题,由我在写ACM习题时想到,在网上并未找到这样的算法,拿出来给大家分享一下,如果网上没有的话,我决定给它起名叫做 CSF迭代法,如果这个算法早已经存在,那就当看个笑话吧。
by 蔡少斐 西安交大 软件53
算法步骤
- 确定一个常数n,表示区间的划分粒度,以及一个常数
eps 表示精度。 先从定义域[l,r]中等差地取出n个点,x1,x2,...,xn。
x1=l+(r−l)n+1,xi=xi−1+r−ln+1
计算f(x1),...,f(xn),挑选出使得f(xt)最大的点xt。
- 判断定义域区间长度是否小于eps,若是执行6,否则执行
5 。 把定义域缩小到[xt−1,xt+1],执行2。
x0=l,xn+1=r
输出xt
算法证明
用反证法:假设存在一次迭代,使得极值点不在[xt−1,xt+1]里面,那么设这个极值点为xp,并且有xp>xt+1,那么可以知道区间[xt−1,xt+1]是单调递增的。也就是说f(xt+1)>f(xt),因此我们在算法的第2个步骤时将选择xt+1而不是xt,矛盾。
因而极值一定在我们所迭代的区间内。
算法复杂度分析
设区间长度为len,划分粒度为n,精度要求为
可以列出递归方程如下:
T(len)=n+T(len(n+1)/2)
其中满足方程:
(2n+1)deplen=eps
解得:
O(len)=nlogepslen2n+1
特殊性
如果令划分粒度n=2的话,等价于三分算法。
算法实现
double csf(double l,double r,int n = 2,double eps = 0.001){ static const double INF = 1e9;double x;while(r - l > eps){double step = (r-l)/(n+1);double mx = -INF;for(double i = l+step;i < r;i += step) if(mx < f(i)) mx = f(i),x = i;l = x-step;r = x+step;}return x;
}
参数分析
函数总共有4个参数l,r,n,eps,其中有3个参数l,r,eps都是给定的。
总是选取l=−10000000,r=10000000
当选取eps=0.001时候
当选取eps=0.000001的时候
结论
n选取
实验代码
#include <bits/stdc++.h>
using namespace std;
double f(double x){return -(x-5)*(x-786);
}
int cnt;
double csf(double l,double r,int n = 2,double eps = 0.001){ static const double INF = 1e9;double x;while(r - l > eps){double step = (r-l)/(n+1);double mx = -INF;for(double i = l+step;i < r;i += step) if(mx < f(i)) mx = f(i),x = i,cnt++;l = x-step;r = x+step;}return x;
}
int main(){freopen("1.csv","w",stdout);for(int i = 2;i <= 100;i+=1) {cnt = 0;double x = csf(-10000000,10000000,i,0.000001);printf("%d,%d\n",i,cnt);}return 0;
}