public class City {
// 地球赤道半径
private static final double ERATH_EQUATORIAL_RADIUS = 6378.1370D;
private static final double CONCVERT_DEGREES_TO_RADIANS = Math.PI / 180;
// 经度
private double longitude;
// 纬度
private double latitude;
// 城市名
private String name;
public City(double longitude,double latitude,String name){
super();
this.longitude=longitude;
this.latitude=latitude;
this.name=name;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
/**
* 计算传入城市与当前城市的实际距离
* @param city
* @return
*/
public double measureDistance(City city){
double deltaLongitude = deg2rad(city.getLongitude() - this.getLongitude());
double deltaLatitude = deg2rad(city.getLatitude() - this.getLatitude());
double a = Math.pow(Math.sin(deltaLatitude / 2D), 2D)
+ Math.cos(deg2rad(this.getLatitude()))
* Math.cos(deg2rad(city.getLatitude()))
* Math.pow(Math.sin(deltaLongitude / 2D), 2D);
return ERATH_EQUATORIAL_RADIUS * 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
}
// 转化为弧度
private double deg2rad(double deg) {
return deg * CONCVERT_DEGREES_TO_RADIANS;
}
}
2 定义路径实体类
public class Route {
private ArrayList cities=new ArrayList<>();
/**
* 构造方法
* 随机打乱cities排序
* @param cities
*/
public Route(ArrayList cities){
this.cities.addAll(cities);
Collections.shuffle(this.cities);
}
public Route(Route route){
for (City city:route.getCities()){
this.cities.add(city);
}
}
/**
* 计算城市间总距离
* @return
*/
public double getTotalDistance() {
int citiesSize = this.cities.size();
double sum = 0D;
int index = 0;
while(index < citiesSize - 1) {
sum += this.cities.get(index).measureDistance(this.cities.get(index + 1));
index++;
}
sum += this.cities.get(citiesSize - 1).measureDistance(this.cities.get(0));
return sum;
}
public String getTotalStringDistance() {
String returnString = String.format("%.2f", this.getTotalDistance());
return returnString;
}
public ArrayList getCities() {
return cities;
}
public void setCities(ArrayList cities) {
this.cities = cities;
}
@Override
public String toString() {
return Arrays.toString(cities.toArray());
}
}
3,定义模拟退火算法
public class SA {
// 最大迭代次数
public static final int ITERATIONS_BEFORE_MAXIMUM = 1500;
public double T=1500;
public static final double T_min=1e-5;
public static final double delta=0.98;
/**
* 模拟退火算法解决TSP问题
* **/
public Route findShortRouteSA(Route currentRoute){
Route adjacentRoute;
int iterToMaximumCounter=0;
String compareRoutes=null;
while (T>T_min){
adjacentRoute=obtainAdjacentRoute(new Route(currentRoute));
if (adjacentRoute.getTotalDistance()<=currentRoute.getTotalDistance()){
compareRoutes = "<= (更新)";
iterToMaximumCounter = 0;
currentRoute = new Route(adjacentRoute);
}else{
double p=Math.random();
if (Math.exp(adjacentRoute.getTotalDistance()-currentRoute.getTotalDistance()/T)>p){
compareRoutes = "<= (更新)";
iterToMaximumCounter = 0;
currentRoute = new Route(adjacentRoute);
}else {
compareRoutes = "> (保持) - 迭代次数 # " + iterToMaximumCounter;
iterToMaximumCounter++;
}
}
System.out.println(" | " + compareRoutes);
System.out.print(currentRoute + " | " + currentRoute.getTotalStringDistance());
T=delta*T;
}
System.out.println(" | 可能的最优解");
return currentRoute;
}
/**
* 随机交换两个城市位置
* @param route
* @return
*/
public Route obtainAdjacentRoute(Route route) {
int x1 = 0, x2 = 0;
while(x1 == x2) {
x1 = (int) (route.getCities().size() * Math.random());
x2 = (int) (route.getCities().size() * Math.random());
}
City city1 = route.getCities().get(x1);
City city2 = route.getCities().get(x2);
// swap two stochastic cities
route.getCities().set(x2, city1);
route.getCities().set(x1, city2);
return route;
}
}
4,定义test类测试
public class Driver {
private ArrayList initialCities = new ArrayList(Arrays.asList(
new City(116.41667, 39.91667, "北京"),
new City(121.43333, 34.50000, "上海"),
new City(113.00000, 28.21667, "长沙"),
new City(106.26667, 38.46667, "银川"),
new City(109.50000, 18.20000, "三亚"),
new City(112.53333, 37.86667, "太原"),
new City(91.00000, 29.60000, "拉萨"),
new City(102.73333, 25.05000, "昆明"),
new City(126.63333, 45.75000, "哈尔滨"),
new City(113.65000, 34.76667, "郑州"),
new City(113.50000, 22.20000, "澳门")));
public static void main(String[] args) {
Driver driver=new Driver();
Route route=new Route(driver.initialCities);
new SA().findShortRouteSA(route);
}
}
5,代码运行结果截图
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 389
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 390
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 391
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 392
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 393
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 394
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 395
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 396
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 397
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 398
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 399
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 400
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 401
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 402
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 403
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 404
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 405
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | > (保持) - 迭代次数 # 406
[北京, 哈尔滨, 上海, 郑州, 长沙, 澳门, 三亚, 昆明, 拉萨, 银川, 太原] | 10085.38 | 可能的最优解
Process finished with exit code 0