计算由广州市出发走遍省内所有市的最短距离。
模拟退火算法:由两规则三函数组成。
两规则指:外层循环结束规则、内层循环结束规则。
三函数指:温度更新函数(控制温度的变化)、状态产生函数(用于产生邻结点)、状态接收函数(用于判断邻结点是否应该被接受)
本代码中退火算法介绍:
外层循环结束规则为:温度小于某个指定的最低温度
内层循环结束规则为:温度步长小于指定值,即每一个温度执行的状态选择次数
状态产生函数为:bulider_neighbor(Node node),根据传入的结点,返回该结点的邻结点ArrayList集合,然后在该集合中随机选取一个结点neighbor,作为新的结点
状态接收函数:接受条件为 neighbor的距离代价value 小于 当前结点(cur_node)的距离代价value或者根据e^-(neighbor.value-cur_node.value)/T (T指当前温度值 Temperature) 计算出一个概率值 P ,若P大于Random[0,1]之间的数,则接受,将新结点neighbor作为当前节点。若不满足上述两个条件,则拒绝接受。
温度更新函数:此处偷懒,选择最简单的Temperature=Temperatrue*a;a的值为小于1的小数即可,保证Temperature的值下降。
package com.AI.Experiment4;
import java.util.ArrayList;
import java.util.Random;
/**
* 模拟退火算法,解决TSP(旅行商)问题
*/
class Node {
public int[] sol; //存放路径
public int value; //存放该路径的距离代价
public Node(int num){
sol=new int[num];
value=Integer.MAX_VALUE;
}
}
public class SA {
private int[][] Dist; //距离矩阵
private float Temperature;//初始温度
private int City_num; //城市数目
private Node cur_node; //初始化结点
private Node best_neighbor; //最优邻结点
private float a; //降温系数
/**
* 传入初始化参数:
* 1.距离矩阵
* 2.初始温度
* @param dist
* @param temperature
*/
public SA(int[][] dist, int temperature,float a) {
Dist = dist;
Temperature = temperature;
this.a=a;
City_num=dist.length;
}
/**
* 将node2的内容复制到node1中
* @param node1
* @param node2
*/
public void CopyNode(Node node1,Node node2){
for(int i=0;i<City_num;i++){
node1.sol[i]=node2.sol[i];
}
node1.value=node2.value;
}
/**
* 模拟退火算法,主函数
* @return
*/
public Node SA_mian(){
//先初始化各个参数
init();
Random random=new Random(); //用于生成随机数
//外层循环退出条件,温度小于0.005
while(Temperature>0.005){
int step=0; //温度步长,内层循环,每一个温度执行200次计算
while(step<1000){
//随机获取当前结点的邻结点
ArrayList<Node> neighbors = builder_neighbors(cur_node);//获取当前结点的邻居结点的集合
int index= random.nextInt(neighbors.size()); //随机邻结点在集合中的下标
Node neighbor=neighbors.get(index); //获取随机邻结点
//判断随机邻结点的距离代价和当前结点的距离代价
if(neighbor.value<cur_node.value){
//符合,则接受该邻居结点作为当前结点
CopyNode(cur_node,neighbor);
CopyNode(best_neighbor,neighbor);
// System.out.println(best_neighbor.value);
}
else{
if(Math.pow(Math.E,-(neighbor.value-cur_node.value)/Temperature)>random.nextDouble()){
CopyNode(cur_node,neighbor);
}
}
step++;
}
Temperature=Temperature*a;
}
return best_neighbor;
}
/**
* 生成传入结点的邻结点集合
* @param node
* @return
*/
public ArrayList<Node> builder_neighbors(Node node){
ArrayList<Node> neighbors=new ArrayList<>();
Node neighbor;//临时变量存放邻居结点
int temp; //临时变量存放城市编号
for(int i=1;i<City_num-1;i++){
for (int j=2;j<City_num;j++){
neighbor=new Node(City_num);
//将当前结点复制给;邻居结点
CopyNode(neighbor,node);
//交换第i个城市和第j个城市的位置
temp=neighbor.sol[i];
neighbor.sol[i]=neighbor.sol[j];
neighbor.sol[j]=temp;
//计算邻居结点的距离代价
neighbor.value=evaluate(neighbor);
//将该邻居结点加入集合
neighbors.add(neighbor);
}
}
return neighbors;
}
//初始化结点
private void init(){
cur_node=new Node(City_num);
best_neighbor=new Node(City_num);
for(int i=0;i<City_num;i++){
cur_node.sol[i]=i;
}
//计算初始化结点的距离代价
cur_node.value=evaluate(cur_node);
//将初始化结点作为最优解结点
CopyNode(best_neighbor,cur_node);
}
/**
* 计算传入结点的距离代价
* @param node
*/
public int evaluate(Node node){
int distance=0;
for(int i=1;i<City_num;i++){
distance=distance+Dist[node.sol[i-1]][node.sol[i]];
}
distance=distance+Dist[node.sol[City_num-1]][node.sol[0]];
return distance;
}
public static void main(String[] args) {
int max=6555;
String[] citys={"广州","佛山","东莞","中山","珠海","深圳","惠州","河源","汕尾","梅州","潮州","汕头","揭阳","清远","韶关","云浮","茂名","湛江","阳江","江门","肇庆"};
int[][] Dist={
{max ,22 ,90 ,86 ,133 ,147 ,148 ,228 ,272 ,426 ,490 ,527 ,465 ,63 ,180 ,145 ,371 ,488 ,225 ,102 ,109 },//广州到各市距离
{22 ,max ,112 ,78 ,128 ,169 ,170 ,250 ,286 ,456 ,520 ,557 ,495 ,85 ,229 ,132 ,349 ,466 ,198 ,66 ,87 },//佛山到各市距离
{90 ,112 ,max ,92 ,132 ,57 ,162 ,134 ,207 ,340 ,404 ,441 ,379 ,153 ,297 ,202 ,461 ,578 ,274 ,122 ,199 },//东莞到各市距离
{86 ,78 ,92 ,max ,25 ,121 ,161 ,240 ,265 ,409 ,420 ,425 ,385 ,158 ,309 ,191 ,317 ,396 ,201 ,43 ,144 },//中山到各市距离
{133 ,128 ,132 ,25 ,max ,162 ,195 ,282 ,307 ,452 ,462 ,467 ,427 ,202 ,354 ,230 ,328 ,407 ,199 ,87 ,193 },//珠海到各市距离
{147 ,169 ,57 ,121 ,162 ,max ,90 ,177 ,169 ,343 ,351 ,333 ,317 ,198 ,324 ,265 ,420 ,499 ,303 ,144 ,218 },//深圳到各市距离
{148 ,170 ,162 ,161 ,195 ,90 ,max ,87 ,130 ,259 ,284 ,289 ,249 ,188 ,271 ,278 ,452 ,531 ,335 ,180 ,231 },//惠州到各市距离
{228 ,250 ,134 ,240 ,282 ,177 ,87 ,max ,219 ,190 ,269 ,286 ,246 ,211 ,251 ,335 ,534 ,613 ,418 ,266 ,288 },//河源到各市距离
{272 ,286 ,207 ,265 ,307 ,169 ,130 ,219 ,max ,221 ,200 ,182 ,165 ,317 ,400 ,407 ,568 ,647 ,452 ,293 ,360 },//汕尾到各市距离
{426 ,456 ,340 ,409 ,452 ,343 ,259 ,190 ,221 ,max ,135 ,155 ,110 ,398 ,360 ,522 ,708 ,787 ,592 ,436 ,475 },//梅州到各市距离
{490 ,520 ,404 ,420 ,462 ,351 ,284 ,269 ,200 ,135 ,max ,49 ,29 ,421 ,439 ,545 ,718 ,797 ,601 ,446 ,498 },//潮州到各市距离
{527 ,557 ,441 ,425 ,467 ,333 ,289 ,286 ,182 ,155 ,49 ,max ,46 ,426 ,466 ,550 ,723 ,802 ,606 ,450 ,503 },//汕头到各市距离
{465 ,495 ,379 ,385 ,427 ,317 ,249 ,246 ,165 ,110 ,29 ,46 ,max ,387 ,413 ,511 ,684 ,763 ,567 ,412 ,464 },//揭阳到各市距离
{63 ,85 ,153 ,158 ,202 ,198 ,188 ,211 ,317 ,398 ,421 ,426 ,387 ,max ,168 ,171 ,379 ,463 ,286 ,151 ,123 },//清远到各市距离
{180 ,229 ,297 ,309 ,354 ,324 ,271 ,251 ,400 ,360 ,439 ,466 ,413 ,168 ,max ,323 ,531 ,615 ,436 ,301 ,293 },//韶关到各市距离
{145 ,132 ,202 ,191 ,230 ,265 ,278 ,335 ,407 ,522 ,545 ,550 ,511 ,171 ,323 ,max ,244 ,328 ,182 ,148 ,56 },//云浮到各市距离
{371 ,349 ,461 ,317 ,328 ,420 ,452 ,534 ,568 ,708 ,718 ,723 ,684 ,379 ,531 ,244 ,max ,96 ,130 ,275 ,267 },//茂名到各市距离
{488 ,466 ,578 ,396 ,407 ,499 ,531 ,613 ,647 ,787 ,797 ,802 ,763 ,463 ,615 ,328 ,96 ,max ,208 ,354 ,348 },//湛江到各市距离
{225 ,198 ,274 ,201 ,199 ,303 ,335 ,418 ,452 ,592 ,601 ,606 ,567 ,286 ,436 ,182 ,130 ,208 ,max ,158 ,201 },//阳江到各市距离
{102 ,66 ,122 ,43 ,87 ,144 ,180 ,266 ,293 ,436 ,446 ,450 ,412 ,151 ,301 ,148 ,275 ,354 ,158 ,max ,104 },//江门到各市距离
{109 ,87 ,199 ,144 ,193 ,218 ,231 ,288 ,360 ,475 ,498 ,503 ,464 ,123 ,293 ,56 ,267 ,348 ,201 ,104 ,max }//肇庆到各市距离
};
int temperature=10000;
float a=0.98f;
SA sa=new SA(Dist,temperature,a);
Node node = sa.SA_mian();
for (int i=0;i<Dist.length;i++){
System.out.print(citys[node.sol[i]]+"\t");
}
System.out.println("最优解的距离代价:"+node.value);
}
}
*注:广东省各市距离矩阵为21*21 ,数据量相对较大,若想得到最优解,需要提高初始温度或温度步长
此解不一定正确,若要得到正确答案,可以多次运行记录下最低解。若计算机性能允许可以将初始温度和温度步长大幅度提高,保证每次都能输出最优解。(本人电脑辣鸡...)
广东省各市间距离(矩阵):
若算法有不足或对算法有不理解的地方,欢迎评论!