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);
}

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