c++實現的模擬退火演算法
演算法簡介
模擬退火演算法得益於材料的統計力學的研究成果。統計力學表明材料中粒子的不同結構對應於粒子的不同能量水平。在高溫條件下,粒子的能量較高,可以自由運動和重新排列。在低溫條件下,粒子能量較低。如果從高溫開始,非常緩慢地降溫(這個過程被稱為退火),粒子就可以在每個溫度下達到熱平衡。當系統完全被冷卻時,最終形成處於低能狀態的晶體。
假定我們要解決的問題是一個尋找最小值的優化問題。將物理學中模擬退火的思想應用於優化問題就可以得到模擬退火尋優方法。
演算法過程
考慮這樣一個組合優化問題:我們現在要求函式f(x)的最小值,其中x∈Sx∈S,S表示函式的定義域,N(x)⊆SN(x)⊆S表示x的一個鄰域集合。
首先給定一個初始溫度T0和該優化問題的一個初始解x(0),並由x(0)生成下一個解x′∈N(x(0))x′∈N(x(0)),是否接受x′x′作為新解x(1)依賴於下面概率:
P(x(0)→x′)={1若f(x′)<f(x(0))e−f(x′)−f(x(0))T0其它P(x(0)→x′)={1若f(x′)<f(x(0))e−f(x′)−f(x(0))T0其它
換句話說,如果生成的解x′x′的函式值比前一個解的函式值更小,則接受x(1)=x′x(1)=x′作為一個新解。否則以概率e−f(x′)−f(x(0))T0e−f(x′)−f(x(0))T0接受x′x′作為一個新解。
同樣的,對於模擬退火過程中任意一個解x(k),接受x′x′作為下一個新解x(k+1)的概率和上面公式類似:
P(x(k)→x′)={1若f(x′)<f(x(k))e−f(x′)−f(x(k))Ti其它P(x(k)→x′)={1若f(x′)<f(x(k))e−f(x′)−f(x(k))Ti其它
整個過程中,溫度Ti不斷下降。模擬退火有概率接受一個更差的解,目的是為了能夠跳出區域性最優,從而尋找全域性最優解。在每個Ti下,所得到的一個新狀態x(k+1)完全依賴於前一個狀態x(k),與前面的狀態x(0),x(1)…,x(k-1)無關,因此是一個馬爾科夫過程。
這裡還有一個結論:如果溫度下降十分緩慢,而且在每個溫度都有足夠多次的狀態轉移,使其在每一個溫度下達到熱平衡,則全域性最優解將以概率1被找到。
模擬退火解決TSP問題
問題:給定平面上20個點的名稱與座標,兩個點之間的距離為它們的歐幾里得距離。求一條路徑,剛好經過每個點1次,使其路徑長度最短。
輸入檔案:in.txt
20
A 2.5 4.0
B 1.2 -2.4
C 8.7 1.2
D 3.6 12.1
E -5.5 0.94
F -6.6 -12.6
G 0.18 5.219
H 12.5 14.3609
I 22.5 -5.26
J 1.61 4.5
K 2.1 -5.6
L 0 25
M 9.2 -32
N -1 7
O -5 -8
P 21 35
Q 16 7.5
R -21 5
S -7 -25.5
T 12 17.5
以下是c++的實現程式碼:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn = 1e2 + 7;
const int INF = 0x7fffffff;
const double PI = acos(-1);
struct Point { //點類
string name;
double x, y;
int i; //編號
};
vector<Point> p;
double d[maxn][maxn]; //距離矩陣
int n;
double sum=0; //當前最短路徑長度
double dist(Point a, Point b) { //計算兩點距離
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double get_sum(vector<Point> a){ //返回路徑長度
double sum=0;
for(int i=1;i<a.size();i++){
sum+=d[a[i].i][a[i-1].i];
}
sum += d[a[0].i][a[a.size()-1].i];
return sum;
}
void init() { //初始化
srand((unsigned)time(NULL)); //設定隨機數種子
cin >> n;
p.clear();
for (int i = 0; i < n; i++) {
Point t;
cin >> t.name >>t.x >>t.y;
t.i=i;
p.push_back(t);
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
d[i][j] = d[j][i] = dist(p[i], p[j]);
}
}
sum=get_sum(p);
}
void Monte_Carlo(){ //蒙特卡洛得到一個較好的初始解
vector<Point> cur=p;
for(int t=0;t<8000;t++){
for(int i=0;i<n;i++){
int j = rand()%n;
swap(cur[i],cur[j]);
}
double new_sum = get_sum(cur);
if(new_sum<sum){
sum=new_sum;
p=cur;
}
}
}
double e=1e-16,at=0.99999999,T=1.0;
//e表示終止溫度 at表示溫度的變化率 T是初始溫度
int L = 200000; //L為最大迭代次數
void Simulated_Annealing(){ //模擬退火
while(L--){ //最多迭代L次
vector<Point> cur=p;
int c1=rand()%n,c2=rand()%n;
if(c1==c2){
L++;continue;
}
swap(cur[c1],cur[c2]);
double df = get_sum(cur) - sum; //計算代價
double sj=rand()%10000; //sj為0~1之間的隨機數
sj/=10000;
if(df < 0){ //如果結果更優,直接接受
p = cur;
sum+=df;
}else if(exp(-df/T)>sj){ //否則以一定概率接受
p = cur;
sum+=df;
}
T*=at; //降溫
if(T<e) break; //T降到終止溫度後退出
}
}
void show(){ //顯示當前結果
cout<<"路徑長度: "<<sum<<endl;
cout<<"路徑:";
for(int i=0;i<n;i++)
cout<<' '<<p[i].name;
puts("");
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
init();
Monte_Carlo();
Simulated_Annealing();
show();
return 0;
}
執行後得到結果(每次執行結果可能不同):
路徑長度: 221.983
路徑: I M S F O R E B K C A J G N D L P T H Q
相關文章
- 模擬退火演算法(1)Python 實現演算法Python
- 模擬退火演算法舉例及其matlab實現演算法Matlab
- 模擬退火演算法解析演算法
- open ... 模擬退火演算法模板演算法
- 模擬退火原理
- 解析·玄學 模擬退火
- 模擬退火與爬山法
- 使用模擬退火演算法優化 Hash 函式演算法優化函式
- 帶約束條件的運籌規劃問題求解(模擬退火演算法實現)演算法
- 模擬退火 學習筆記筆記
- 模擬退火學習筆記筆記
- 自己用C語言寫的一個模擬退火演算法C語言演算法
- c++模擬實現順序表C++
- 模擬退火演算法Python程式設計(4)旅行商問題演算法Python程式設計
- 棧的模擬實現及常見演算法演算法
- 模擬退火演算法Python程式設計(2)約束條件的處理演算法Python程式設計
- promise的模擬實現Promise
- 模擬退火演算法Python程式設計(3)整數規劃問題演算法Python程式設計
- C++進階(map+set容器模擬實現)C++
- C++ 實現銀行排隊服務模擬C++
- javascript模擬new的實現JavaScript
- JavaScript 模擬new的實現JavaScript
- C++進階(unordered_set+unordered_map模擬實現)C++
- javascript模擬實現replaceAll()JavaScript
- svpwm的matlab模擬實現Matlab
- strlen函式的模擬實現函式
- 基於MATLAB的指紋識別演算法模擬實現Matlab演算法
- qsort的模擬實現和練習
- JavaScript深入之new的模擬實現JavaScript
- JavaScript深入之bind的模擬實現JavaScript
- JavaScript 深入之new的模擬實現JavaScript
- JavaScript 深入之bind的模擬實現JavaScript
- BZOJ2428 [HAOI2006]均分資料 模擬退火
- 【Java】——模擬登入實現Java
- JavaScript模擬實現replaceAll方法JavaScript
- 用vc執行緒模擬實現並行演算法 (轉)執行緒並行演算法
- js實現的模擬滾動條效果JS
- 模擬STL連結串列類的實現