模擬退火


一、什么是模擬退火算法

1、爬山算法

在了解模擬退火算法之前,先來看一下爬山算法:爬山算法是一種貪心算法,該算法每次從當前的解空間中選取一個解作為最優解,直到達到一個局部最優解。假設函數f(x)的圖像如下圖:

現在使用爬山算法來求f(x)的最大值,若C為當前最優解,則爬山算法搜索到A就會停止搜索,這會獲得一個局部最優解,而不是全局最優解。

模擬退火:繼續考慮尋找f(x)最大值的問題,爬山算法搜索到A點時就會停止搜索,原因是A點左右的值均小於A點的值。模擬退火算法采用的解決辦法是以一定的概率選擇A兩邊的點,盡管A兩邊的點並不是局部最優解,這樣就有一定的概率搜索到D點,從而搜索到B點,最終獲得了全局最優解。

2、模擬退火算法

 

現在想求函數的(全局)最優解。如果采用Greedy策略,那么從A點開始試探,如果函數值繼續減少,那么試探過程就會繼續。而當到達點B時,顯然我們的探求過程就結束了(因為無論朝哪個方向努力,結果只會越來越大)。最終我們只能找打一個局部最后解B。

模擬退火其實也是一種Greedy算法,但是它的搜索過程引入了隨機因素。模擬退火算法以一定的概率來接受一個比當前解要差的解,因此有可能會跳出這個局部的最優解,達到全局的最優解。以上圖為例,模擬退火算法在搜索到局部最優解B后,會以一定的概率接受向右繼續移動。也許經過幾次這樣的不是局部最優的移動后會到達B 和C之間的峰點,於是就跳出了局部最小值B。

模擬退火算法(Simulate Anneal,SA)是一種通用概率演算法,用來在一個大的搜尋空間內找尋命題的最優解

    爬山算法:兔子朝着比現在高的地方跳去。它找到了不遠處的最高山峰。但是這座山不一定是珠穆朗瑪峰。這就是爬山算法,它不能保證局部最優值就是全局最優值。

  模擬退火:兔子喝醉了。它隨機地跳了很長時間。這期間,它可能走向高處,也可能踏入平地。但是,它漸漸清醒了並朝最高方向跳去。這就是模擬退火。

使用模擬退火算法解決旅行商問題

旅行商問題(TravelingSalesmanProblem,TSP)是一個經典的組合優化問題。經典的TSP可以描述為:一個商品推銷員要去若干個城市推銷商品,該推銷員從一個城市出發,需要經過所有城市后,回到出發地。應如何選擇行進路線,以使總的行程最短。該問題可以使用模擬退火算法解決,C++代碼如下:

 

使用模擬退火算法可以比較快的求出TSP的一條近似最優路徑。(使用遺傳算法也是可以的,我將在下一篇文章中介紹)模擬退火解決TSP的思路:

 

1. 產生一條新的遍歷路徑P(i+1),計算路徑P(i+1)的長度L( P(i+1) )

 

2. 若L(P(i+1)) < L(P(i)),則接受P(i+1)為新的路徑,否則以模擬退火的那個概率接受P(i+1) ,然后降溫

 

3. 重復步驟1,2直到滿足退出條件

 

  產生新的遍歷路徑的方法有很多,下面列舉其中3種:

 

1. 隨機選擇2個節點,交換路徑中的這2個節點的順序。

 

2. 隨機選擇2個節點,將路徑中這2個節點間的節點順序逆轉。

 

3. 隨機選擇3個節點m,n,k,然后將節點m與n間的節點移位到節點k后面。

 

#include <iostream> #include <string.h> #include <stdlib.h> #include <algorithm> #include <stdio.h> #include <time.h> #include <math.h> #define N 30 //城市數量 #define T 3000 //初始溫度 #define EPS 1e-8 //終止溫度 #define DELTA 0.98 //溫度衰減率 #define LIMIT 1000 //概率選擇上限 #define OLOOP 20 //外循環次數 #define ILOOP 100 //內循環次數 using namespace std; //定義路線結構體 struct Path { int citys[N]; double len; }; //定義城市點坐標 struct Point { double x, y; }; Path bestPath; //記錄最優路徑 Point p[N]; //每個城市的坐標 double w[N][N]; //兩兩城市之間路徑長度 int nCase; //測試次數 double dist(Point A, Point B) { return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y)); } void GetDist(Point p[], int n) { for(int i = 0; i < n; i++) for(int j = i + 1; j < n; j++) w[i][j] = w[j][i] = dist(p[i], p[j]); } void Input(Point p[], int &n) { scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%lf %lf", &p[i].x, &p[i].y); } void Init(int n) { nCase = 0; bestPath.len = 0; for(int i = 0; i < n; i++) { bestPath.citys[i] = i; if(i != n - 1) { printf("%d--->", i); bestPath.len += w[i][i + 1]; } else printf("%d\n", i); } printf("\nInit path length is : %.3lf\n", bestPath.len); printf("-----------------------------------\n\n"); } void Print(Path t, int n) { printf("Path is : "); for(int i = 0; i < n; i++) { if(i != n - 1) printf("%d-->", t.citys[i]); else printf("%d\n", t.citys[i]); } printf("\nThe path length is : %.3lf\n", t.len); printf("-----------------------------------\n\n"); } Path GetNext(Path p, int n) { Path ans = p; int x = (int)(n * (rand() / (RAND_MAX + 1.0))); int y = (int)(n * (rand() / (RAND_MAX + 1.0))); while(x == y) { x = (int)(n * (rand() / (RAND_MAX + 1.0))); y = (int)(n * (rand() / (RAND_MAX + 1.0))); } swap(ans.citys[x], ans.citys[y]); ans.len = 0; for(int i = 0; i < n - 1; i++) ans.len += w[ans.citys[i]][ans.citys[i + 1]]; cout << "nCase = " << nCase << endl; Print(ans, n); nCase++; return ans; } void SA(int n) { double t = T; srand((unsigned)(time(NULL))); Path curPath = bestPath; Path newPath = bestPath; int P_L = 0; int P_F = 0; while(1) //外循環,主要更新參數t,模擬退火過程  { for(int i = 0; i < ILOOP; i++) //內循環,尋找在一定溫度下的最優值  { newPath = GetNext(curPath, n); double dE = newPath.len - curPath.len; if(dE < 0) //如果找到更優值,直接更新  { curPath = newPath; P_L = 0; P_F = 0; } else { double rd = rand() / (RAND_MAX + 1.0); //如果找到比當前更差的解,以一定概率接受該解,並且這個概率會越來越小 if(exp(dE / t) > rd && exp(dE / t) < 1) curPath = newPath; P_L++; } if(P_L > LIMIT) { P_F++; break; } } if(curPath.len < bestPath.len) bestPath = curPath; if(P_F > OLOOP || t < EPS) break; t *= DELTA; } } int main(int argc, const char * argv[]) { freopen("TSP.data", "r", stdin); int n; Input(p, n); GetDist(p, n); Init(n); SA(n); Print(bestPath, n); printf("Total test times is : %d\n", nCase); return 0; }
View Code

 

轉自:https://www.cnblogs.com/sench/p/9427193.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM