日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法

發布時間:2023/12/3 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下均假設最優解是在最低點。

爬山法

爬山算法是一種局部擇優的方法,采用啟發式方法,是對深度優先搜索的一種改進,它利用反饋信息幫助生成解的決策。

直白地講,就是當目前無法直接到達最優解,但是可以判斷兩個解哪個更優的時候,根據一些反饋信息生成一個新的可能解。

因此,爬山算法每次在當前找到的最優方案 xxx 附近尋找一個新方案。如果這個新的解 x′x'x 更優,那么轉移到 x′x'x,否則不變。

這種算法對于單峰函數顯然可行。

Q:既然都知道是單峰函數了為什么不三分呢?

A:你說的對!直接三分好了。

B:我要是知道是單峰函數,我還在這里騙分???

爬山算法會引入『溫度參數』 TTT

類比的說,爬山就是一個醉漢喝得狂醉然后再山上裸奔蹦迪。

他知道該回家了(不然就要跪搓衣板),然后每次會往他認為最低的地方狂奔過去(中途不剎車)。

顯然他可能一次恰好奔到山腳然后下山回家,也有可能奔過了到另一座山頂上去了。

不過沒關系,醉漢奔過頭了還會存在奔回來的可能。

但顯然這個過程很沒用。仿佛醉漢回家全靠天公作美。

所以在暴走過程中,他會經受山頂寒風的摧殘,酒精作用漸漸消減,他變得越發清晰。

他就變得謹慎一點,每次少奔一點以達到山腳最低點位置。

這就要引入『降溫參數』來起到緩緩冷靜的作用。

關于『降溫參數』,一般是 [0.985,0.999][0.985,0.999][0.985,0.999] 中選,這樣才能做到慢慢消減。

顯然如果存在多個”轉折“時,爬山就很容易進入局部最優解,而非全局最優解。

隨著頭腦逐漸清醒,醉漢蹦出局部最優解的期望就會更小,很有可能一直跳不過去某個坡。

模擬退火

為什么會有上面情況的產生呢?

其實是因為爬山法的寫法,只有在新解優于當前解的時候,我們才會接受新解并移動到相應位置。

根據這種情況,我們知道其實偶爾新解不好我們也要去接受,這樣才會存在跳出這個坡的可能。

這就是模擬退火了。

模擬退火相較于爬山就只是多了一個隨機接受非最優解的部分,大大增加了找到全局最優解得可能。

以下是追根溯源,由物理和化學知識遷移到信息學上應用:

我們知道在分子和原子的世界中,能量越大,意味著分子和原子越不穩定,當能量越低時,原子越穩定。

『退火』是物理學術語,指對物體加溫在冷卻的過程。

模擬退火算法來源于晶體冷卻的過程,如果固體不處于最低能量狀態,給固體加熱再冷卻,隨著溫度緩慢下降,固體中的原子按照一定形狀排列,形成高密度、低能量的有規則晶體(即全局最優解)。

而如果溫度下降過快,可能導致原子缺少足夠的時間排列成晶體的結構,結果產生了具有較高能量的非晶體(即局部最優解)。

因此就可以根據退火的過程,給其再增加一點能量,然后再冷卻,如果增加能量,跳出了局部最優解,那么本次退火就是成功的。

模擬退火由兩個部分組成:Metropolis\text{Metropolis}Metropolis 算法和退火過程。

Metropolis\text{Metropolis}Metropolis 算法就是如何在局部最優解的情況下讓其跳出來,是退火的基礎。

Metropolis\text{Metropolis}Metropolis 提出的以概率來接受新狀態的重要性采樣方法,而非使用完全確定的規則,稱為Metropolis\text{Metropolis}Metropolis 準則,計算量較低。

假設我們從 AAA 開始求解。先跳到 BBB,然后發現 BBB 更優,絕對接受。BBB 又跳到 CCC,絕對接受。CCC 跳到 DDD ,哎呀更差了呢!此時我們以一定的概率選擇是否接受;假設接受,DDD 又跳到 EEE 發現比之前跳到的所有位置都優,直接接受,EEE 繼續跳……\dots\dots ;不接受,就還停在 CCC 又開始隨機下一個解。

至于這個接受概率是多少呢?已經有前人計算出來了。x:x:x: 當前最優解,x′:x':x: 產生的新解
P={1E(x′)<E(x)e?E(x′)?E(x)TE(x′)≥E(x)P=\begin{cases}1\quad\quad\quad\quad\quad\quad E(x')<E(x)\\e^{-\frac{E(x')-E(x)}{T}}\quad\quad\ E(x')\ge E(x)\end{cases} P={1E(x)<E(x)e?TE(x)?E(x)??E(x)E(x)?
從這個式子我們可以看出,如果新解更優,那么百分之百絕對接受;否則我們會以 PPP 的概率接受。

Metropolis\text{Metropolis}Metropolis 算法雖然說是模擬退火算法的基礎,但直接使用的話可能導致尋找解得速度太慢,以至于無法過題。

為了確保在有限的時間收斂,必須設定控制算法收斂的參數。

在上面的公式中,可以調節的參數就是『溫度參數』TTT

  • TTT 如果過大,就會導致退火太快,迭代次數不夠,最后停留在局部最優值就會結束迭代。
  • TTT 如果較小,則計算時間會增加。

實際應用中采用退火溫度表,在退火初期采用較大的 TTT 值,隨著退火的進行,逐步降低:

  • 初始的溫度 T0T_0T0? 應選的足夠高,使的所有轉移狀態都被接受。初始溫度越高,獲得高質量的解的概率越大,但耗費的時間也越長。

  • 退火速率。

    • 指數式下降:Tn=λTn,n=1,2,3,...T_n=\lambda T_n,n=1,2,3,...Tn?=λTn?,n=1,2,3,...λ\lambdaλ 即是爬山算法里面的『降溫參數』,選取的值同樣遵守 <1<1<1 又逼近 111 原則。

      這種方式最常見,且對每一溫度,有足夠的轉移嘗試,但其收斂速度比較慢。

    • 其它方式:

      • Tn=T0log?(1+t)T_n=\frac{T_0}{\log(1+t)}Tn?=log(1+t)T0??
      • Tn=T01+tT_n=\frac{T_0}{1+t}Tn?=1+tT0??
  • 終止溫度。當 T0T_0T0? 迭代到終止溫度時就會結束退火。一般設為 eps=1e-k(k∈Z+k\in \Z^+kZ+)。

一般針對數據進行『溫度參數』TTT,『降溫參數』Δ\DeltaΔ 的調參,在本地手造大數據跑,自己抉擇。

對時間和正確性的平衡選取。

有的時候可以用 #include <ctime> 庫里面自帶的 clock() 函數計時,也可以自己定一個跑的次數。

( clock() / (1.0 * CLOCKS_PER_SEC) ) <= TIME //返回的是多少秒 所以TIME是個 <1 的浮點數

需要注意是:

  • 初始溫度 T0T_0T0? 的選取對算法結果有一定的影響,最好是多次運行對結果進行綜合判斷。
  • 在算法運行初期,溫度下降快,避免接受過多的差結果。當運行時間增加,溫度下降減緩,以便于更快穩定結果。
  • 當迭代次數增加到一定次數時,結果可能已經達到穩定,但是距離算法結束還有一段時間。在設計程序時應該加入適當的輸出條件,滿足輸出條件即可結束程序。

最后給出流程圖總結:又淘了一張好圖

顯然,模擬退火也不一定是對的,這個概率接受就很概率。但對比爬山得到最優解的概率肯定是大大增加的。

例題

Strange function

hdu2899

TTT 次詢問,每次給定 yyy

f(x)=6x7+8x6+7x3+5x2?yx(0≤x≤100)f(x)=6x^7+8x^6+7x^3+5x^2-yx\quad(0\le x\le 100)f(x)=6x7+8x6+7x3+5x2?yx(0x100) 的最小值。

#include <bits/stdc++.h> using namespace std; double y; const double eps = 1e-8; //終止溫度 const double delta = 0.997; //溫度變化率 mt19937 wwl(time(0)); uniform_real_distribution < double > range( 0, 100 );double f( double x ) {return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * pow(x, 2) - y * x; }double solve() {double T = 100, x = range( wwl ); //初始溫度 以及初始隨機解double now = f(x), ans = now;int Time = 8e5; //防止超時的卡點次數while( T > eps and Time -- ) { //要么降溫完成 要么被卡時double tx = x + (rand() * 2 - RAND_MAX) * T; //隨機擾動產生新解if( 0 <= tx and tx <= 100 ) {double nxt = f(tx);ans = min( ans, nxt );if( nxt < now ) //新狀態更小 直接接受x = tx, now = nxt;else if( rand() < exp( ( now - nxt ) / T ) * RAND_MAX ) //在一定概率內仍接受這個解x = tx, now = nxt;}T *= delta; //降溫}return ans; }int main() {int T;scanf( "%d", &T );while( T -- ) {scanf( "%lf", &y );printf( "%.4f\n", solve() );}return 0; }

[JSOI2004]平衡點 / 吊打XXX

洛谷鏈接

#include <bits/stdc++.h> using namespace std; #define delta 0.996 #define maxn 1005 #define eps 1e-15 struct node { int x, y, w; }g[maxn]; int n;double energy( double x, double y ) {double ans = 0, dx, dy;for( int i = 1;i <= n;i ++ ) {dx = x - g[i].x, dy = y - g[i].y;ans += sqrt( dx * dx + dy * dy ) * g[i].w;}return ans; }double ansx, ansy, ans, x, y, now; void Simulate_Anneal() {double T = 5e4;while( T > eps ) {double tx = x + (rand() * 2 - RAND_MAX) * T;double ty = y + (rand() * 2 - RAND_MAX) * T;double tw = energy( tx, ty );if( tw < ans ) ans = tw, ansx = tx, ansy = ty;if( tw < now ) x = tx, y = ty, now = tw;else if( rand() < exp( ( now - tw ) / T ) * RAND_MAX )x = tx, y = ty;T *= delta;} }signed main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ )scanf( "%d %d %d", &g[i].x, &g[i].y, &g[i].w );for( int i = 1;i <= n;i ++ ) x += g[i].x, y += g[i].y;x /= n, y /= n;ansx = x, ansy = y;now = ans = energy( x, y );Simulate_Anneal();Simulate_Anneal();Simulate_Anneal();Simulate_Anneal();printf( "%.3f %.3f\n", ansx, ansy );return 0; }

Haywire

洛谷鏈接

#include <bits/stdc++.h> using namespace std; #define TIME 0.9 #define eps 1e-10 #define delta 0.998 #define maxn 15 int n; int p[maxn]; int f[maxn][5];int energy() {int ans = 0;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= 3;j ++ )ans += fabs( p[i] - p[f[i][j]] );return ans; }int main() {mt19937 wwl(time(NULL));scanf( "%d", &n );uniform_int_distribution < int > id( 1, n );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= 3;j ++ )scanf( "%d", &f[i][j] );iota( p + 1, p + n + 1, 1 );int ans = energy();while( ( clock() / (1.0 * CLOCKS_PER_SEC) ) <= TIME ) {for( int i = 1;i <= n;i ++ ) p[i] = i;double T = 1e5; int x, y;while( T > eps ) {do { x = id( wwl ), y = id( wwl ); }while( x == y );swap( p[x], p[y] );int now = energy();if( now < ans ) ans = now;else if( rand() > exp( ( now - ans ) / T ) * RAND_MAX )swap( p[x], p[y] );T *= delta;}}printf( "%d\n", ans / 2 );return 0; }

學習參考博客:

https://www.cnblogs.com/flashhu/p/8884132.html

https://blog.csdn.net/weixin_42398658/article/details/84031235

https://zhuanlan.zhihu.com/p/266874840?utm_source=qq

總結

以上是生活随笔為你收集整理的【学习笔记】我命由天不由我之随机化庇佑 —— 爬山法 和 模拟退火法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。