【概述】
爬山法(Hill Climbing,HC)是一種局部擇優的貪心搜索算法,其本質上是梯度下降法。
該算法每次從當前的節點開始,與周圍的鄰接點進行比較:
- 若當前節點是最大的,那麼返回當前節點,作爲最大值
- 若當前節點是最小的,就用最高的鄰接點替換當前節點,從而實現向山峯的高處攀爬的目的
如此循環往復,直到達到最高點爲止。
但該算法的主要問題是:局部最大,即某個節點會比周圍任何一個鄰居都高,但只是局部最優解,並非全局最優解。
如下圖,在處於當前解時,爬山法搜索到局部最優解後,就會停止搜索,因爲在局部最優解這個點,無論向哪個方向小幅度的移動,都無法得到更優解
此外,其還存在以下兩種問題:
- 高地問題:搜索一旦到達高地,就無法確定搜索最佳方向,會產生隨機走動,使得搜索效率降低
- 山脊問題:搜索可能會在山脊的兩面來回震盪,前進步伐很小
當出現以上問題後,只能隨機重啓爬山算法來解決。
【主要思路】
首先,隨機選擇一個登山的初始時間 T,這個參數是隨機選擇的
然後,只要當 T 大於一個邊界值 EPS 時,就將當前點與其鄰接點進行比較:
- 如果 res<newRes,轉移答案,並記錄新座標點 pos
- 如果 res>newRes,不轉移
之後,根據記錄下來的新座標點 pos,去轉移狀態,一般爲:sta = sta + (node[pos] - sta) * T;
最後,對 T 乘以一個小於但十分接近於 1 的數 delta,以體現時間對答案的影響。
不斷重複上述步驟,直到鄰接點中不再有比起大的點。
int getPos(double x) {//比較答案並獲取新座標點
int pos;//新座標點
double res = -INF;
for (int i = 1; i <= n; i++) {
double newRes = getRes(x, node[i]);//獲取新狀態答案
if (newRes > res) { //比較答案
res = newRes; //更新結果
pos = i; //記錄新座標點
}
}
return pos;
}
void HC(double &x,double &y) {
double T = 1;
while (T > EPS) {
int pos = getPos(x);//獲取下一狀態的座標
sta = sta + (node[pos] - x) * T;//轉移x狀態
T *= 0.96;
}
}