【模擬退火】解決【TSP】問題
阿新 • • 發佈:2018-11-30
TSP問題求解
n個城市之間有一定距離,現在讓選擇一個城市出發,然後到達所有的城市,最後回到原點每個城市只到達一次,求出一條路徑並且求出最短的距離
TSP問題是一個NP問題,但是可以求近似解,通過模擬退火演算法實現,
源:https://blog.csdn.net/acdreamers/article/category/1160225/4
#include <iostream> #include <string.h> #include <stdlib.h> #include <algorithm> #include <stdio.h> #include <time.h> #include <math.h> //#define LOCAL #define N 30 //城市數量 #define T 3000 //初始溫度(最大距離) #define EPS 1e-8 //終止平衡溫度(精度) #define DELTA 0.98 //溫度衰減速率 (會控制最優解) #define LIMIT 10000 //概率選擇上限 (控制最優解) #define OLOOP 1000 //外迴圈次數 (控制時間複雜度) #define ILOOP 15000 //內迴圈次數 ... using namespace std; struct Path { int citys[N];double len; }; //定義路線結構體 struct Point { double x, y; }; //定義城市座標 Path path; //記錄最優路徑 Point p[N]; //每個城市的座標 double dis[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 GetDis(Point p[], int n) { for (int i = 0;i < n;++i) for (int j = 0;j < n;++j) dis[i][j] = dis[j][i] = dist(p[i], p[j]); } void Input(Point p[], int &n) { scanf("%d", &n); for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;//scanf("%f %f", &p[i].x, &p[i].y); } void Init(int n) { nCase = 0; path.len = 0; for (int i = 0; i < n; i++) { path.citys[i] = i; if (i != n - 1) { printf("%d--->", i); path.len += dis[i][i + 1]; } else printf("%d\n", i); } printf("Init path length is : %.4f\n", path.len); } 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("The path length is : %.4f\n", t.len); } 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 += dis[ans.citys[i]][ans.citys[i + 1]]; cout << "nCase = " << nCase; Print(ans, n); //中間結果輸出 nCase++; //測試樣例,可看時間複雜度 return ans; } void SA(int n) { double t = T; //開始溫度 srand(time(NULL)); Path curPath = path; Path newPath = path; 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) //降溫成功,找到的 newPath 是當前更優 { 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 < newPath.len) path = curPath; if (P_F > OLOOP || t < EPS) break; t *= DELTA; } } int main() { //freopen("TSP.data", "r", stdin); #ifdef LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif // LOCAL int n; Input(p, n); GetDis(p, n); Init(n); SA(n); Print(path, n); //path 是最終的結果 printf("Total test times is : %d\n", nCase); return 0; }