使用退火算法来解决最优路径的思考
-
概述
旅行商问题一直认为是一个NP问题,除了穷举外,没有最优解,只有近似解 -
解决方案
下面提供了使用一个网上使用模拟退火算法来做的代码#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 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 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; path.len = 0; for(int i = 0; i < n; i++) { path.citys[i] = i; if(i != n - 1) { printf("%d--->", i); path.len += w[i][i + 1]; } else printf("%d\n", i); } printf("\nInit path length is : %.3lf\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("\nThe path length is : %.3lf\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 += 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(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) //如果找到更优值,直接更新 { 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); int n; Input(p, n); GetDist(p, n); Init(n); SA(n); Print(path, n); printf("Total test times is : %d\n", nCase); return 0; }
-
效果
- 局限性
- 不支持大数据量,如果有几十万个城市,这个内存都很难支持
- 算法实在太耗时了,有很大改善区间
- 不够灵活,如不可制定入口和出口
- 实际运用场景
- 高尔球场开小车捡球
- PCB板钻孔的路径规划