homework: 组合最优化之一维搜索:fibnacci搜索/进退法求极值区间

问题描述:

给定函数f(x)=x2x+2f(x)=x^2-x+2,设计fibnacci算法,进退算法分别求f(x)f(x)在区间[0,3]上的极小值区间,要求区间长度不大于原始区间的 9%9\%

Fibnacci算法:

算法设计:

给定区间[a,b][a,b]以及精度ee,函数f(x)f(x)

①预处理出一定数量的斐波那契数列fib,fib[0]=fib[1]=1,fib[n]=fib[n1]+fib[n2]fib,fib[0]=fib[1]=1,fib[n]=fib[n-1]+fib[n-2],然后根据求解区间和求解精度得到计算次数n。因为我们设定间隔两个单位区间长度的时候结束,所以f[n+1]>=2(ba)/ef[n+1] >=2(b-a)/e
②令x1=bfib[n]/fib[n+1](ba),x2=a+fib[n]/fib[n+1](ba)x1 =b-fib[n]/fib[n+1]*(b-a), x2 = a + fib[n]/fib[n+1]*(b-a)

③判断ba|b -a|是否小于等于ee,如果是,则结束计算,得到结果区间[a,b][a,b],否则比较f(x1)f(x1)
f(x2)f(x2)的大小,若f(x1)>f(x2)f(x1) > f(x2),跳到④,否则跳到⑤。

④令a=x1,x1=x2,x2=a+bx1a = x1, x1 = x2, x2 = a + b - x1.跳到③

⑤令b=x2,x2=x1,x1=a+bx2b = x2, x2 = x1, x1 = a + b - x2.跳到③

代码实现:

#include<bits/stdc++.h>
using namespace std;
int fib[40];
double f(double x){
    return x*(x-1)+2;
}
void init(){
    fib[0] = 1; fib[1] = 1; for(int i = 2; i < 40; ++i) fib[i] = fib[i-1] + fib[i-2];
}
void sol(double l, double r, double eps){
    int s = 2*(r-l)/eps+1;
    int n = 0;
    while(fib[n+1] <= s) ++n;//获取迭代次数
    double lmid = r - (double)fib[n]/fib[n+1] * (r-l);
    double rmid = l + (double)fib[n]/fib[n+1] * (r-l);
    int ca = 0;
    while(r-l > eps){
        cout<<setprecision(4)<<fixed<<"test"<<++ca<<": l = "<<l<<"    r = "<<r<<"    lmid = "<<lmid<<"    rmid:"<<rmid;
        cout<<"    f(lmid) = "<<f(lmid)<<"    f(rmid) = "<<f(rmid)<<endl<<endl;
        if(f(lmid) > f(rmid)){
            l = lmid;
            lmid = rmid;
            rmid = l + r - lmid;
        }
        else{
            r = rmid;
            rmid = lmid;
            lmid = l + r - rmid;
        }
    }

    cout<<"\n result : \nl:"<<l<<" r:"<<r<<endl;
}
int main()
{
	init();
	double l, r;cout<<"输入搜索区间:"; cin>>l>>r;
	sol(l, r, (r-l)*0.09);
}

进退法:

ps: 这里写的进退法经过修改,在找到单峰但是不满足精度的时候通过减少步长来继续下降。不知道还算不算进退法:D

算法设计:

给定初始点xx,精度ee和函数f(x)f(x),初始步长h0h_0

①先确定很小的步数dx=e/100dx=e/100,比较f(x0+dx),f(x)f(x0+dx),f(x)f(xdx)f(x-dx)来确定下降方向,若f(x+dx)<f(x)<f(xdx)f(x+dx)<f(x)<f(x-dx),令dx=h0dx=h0,若f(x+dx)>f(x)>f(xdx)f(x+dx)>f(x)>f(x-dx),令dx=h0dx = -h0,否则可确定[xdx,x+dx][x-dx,x+dx]为满足条件的区间,结束算法。

②令x1=x+dx,x2=x1+dxx1 = x+dx, x2 = x1+dx.如果f(x)>f(x1)>f(x2)f(x)>f(x1)>f(x2),转③,否则如果x2x<=e|x2-x|<=e,已经找到满足条件单峰区间[x,x2][x,x2],结束算法。如果x2x>e|x2-x|>e,转④

③令x=x1,dx=dx2x = x1, dx = dx*2。转②

④令dx=dx/2dx = dx/2。转②

代码实现:

#include<bits/stdc++.h>
using namespace std;
double f(double x){
    return x*(x-1)+2;
}
void sol(double x0, double eps, double h0){
    double dx = eps/100;
    double x1, x2;
    if(f(x0) < f(x0 + dx) && f(x0) < f(x0 - dx)) {
        cout<<"结果区间为:["<<x0-dx<<","<<x0+dx<<"]\n";return;
    }
    else if(f(x0) > f(x0 + dx)) dx = h0;
    else dx = -h0;
    int num = 0;
    while(1){
        num++;
        x1 = x0 + dx;  x2 = x1 + dx;
        cout<<setprecision(3)<<fixed<<"x0 = "<<x0<<"\tx1 = "<<x1<<"\tx2 = "<<x2;
        cout<<"\tf(x0) = "<<f(x0)<<"\tf(x1) = "<<f(x1)<<"\tf(x2) = "<<f(x2)<<endl;
        if(f(x0) > f(x1) && f(x1) > f(x2)){
            x0 = x1;
            dx = dx*2.0;
            continue;
        }
        else{
            if(abs(x2-x0) > eps){
                dx = dx/2.0;
            }
            else{
                cout<<"迭代次数:"<<num<<endl;
                cout<<"结果区间为:["<<min(x0,x2)<<","<<max(x0, x2)<<"]\n";return;
            }
        }
    }
}
int main()
{
	double x0, e, h0;
	cout<<"输入初始点:";cin>>x0;
    cout<<"输入需求区间精度:";cin>>e;
    cout<<"输入初始步长:";cin>>h0;
    sol(x0, e, 0.1);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章