1. 程式人生 > >旅行商問題的模擬退火解法

旅行商問題的模擬退火解法

問題描述:
一名商人要去n個城市推銷產品,他需要經過每個城市一次且僅一次,最後回到出發的城市,問最短路徑長度是多少。
資料:

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

程式碼:

struct city//城市
{ char name;//名字 int id;//下標 double x; double y; }; int n;//城市數 vector<city> v;//路徑 double dist[110][110];//鄰接矩陣 double sum = 0;//路徑長度 double dis(city a,city b)//計算兩點間的距離 { return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } double get_sum(vector<city> v)//獲取當前路徑的長度 { double
sum = 0; for(int i = 1; i <= v.size() - 1; ++i) sum += dist[v[i].id][v[i - 1].id]; sum += dist[v[0].id][v[v.size() - 1].id];//注意是迴路 return sum; } void monte_carlo()//蒙特卡洛 { vector<city> cur = v; for(int k = 1; k <= 8000; ++k)//8000次迴圈 { for(int i = 0; i <= n - 1
; ++i) { int j = rand() % n; swap(cur[i],cur[j]);//隨機交換兩個數 } } double cur_sum = get_sum(cur);//計算路徑長度 if(cur_sum < sum)//如果比當前路徑短 { sum = cur_sum;//更新 v = cur;//更新 } return; } double end_of_t = 1e-16;//結束時的溫度 double rate_of_t = 0.99999999;//溫度下降的比率 double T = 1.0;//溫度,初始為1.0 int cnt = 200000;//最多迭代2w次 void simulated_annealing()//模擬退火 { while(cnt--) { vector<city> cur = v; int r1 = rand() % n; int r2 = rand() % n; if(r1 == r2)//如果隨機數相等 { cnt++; continue;//重新生成 } swap(cur[r1],cur[r2]);//交換 double df = get_sum(cur) - sum;//計算路徑長度的改變數 double r3 = (rand() % 10000) / 10000.0;//隨機數r3 if(df < 0)//如果更短,則接受 { v = cur; sum += df;// += } else if(exp(-df / T) > r3)//否則按照一定的概率(不等式的左邊)接受 { v = cur; sum += df;// += } T = T * rate_of_t;//溫度下降 if(T < end_of_t)//如果到達最低溫度 break; } return; } void print_ans()//輸出答案 { cout << "路徑長度為:" << sum << endl; cout << "路徑為:"; for(int i = 0; i <= n - 1; ++i) cout << v[i].name << ' '; cout << endl; return; } int main() { cin >> n; srand((unsigned int)time(NULL));//初始化隨機數種子 for(int i = 0; i <= n - 1; ++i) { city t; cin >> t.name >> t.x >> t.y; t.id = i; v.push_back(t); } for(int i = 0; i <= n - 2; ++i)//求出鄰接矩陣 for(int j = i + 1; j <= n - 1; ++j) dist[i][j] = dist[j][i] = dis(v[i],v[j]); sum = get_sum(v);//初始路徑長度 monte_carlo();//生成初始解 simulated_annealing();//模擬退火 print_ans();//輸出答案 return 0; }

解決方法:
模擬退火演算法