数学建模常用算法:蚁群算法求解tsp问题+att48算例测试【java实现--详细注释】

简介: 数学建模常用算法:蚁群算法求解tsp问题+att48算例测试【java实现--详细注释】

代码

蚂蚁类

package com.dam.heuristic.aco.test;
import java.util.*;
public class Ant {
    //蚂蚁所走的城市序列
    private List<Integer> sequence;
    //未访问的城市
    private LinkedHashSet<Integer> unVisitedCities;
    //信息素变化矩阵
    private double[][] delta;
    //距离矩阵
    private double[][] distanceMatrix;
    //信息素重要程度因子,其值越大,表示信息素的浓度在转移中起的作用越大
    private double alpha;
    //启发函数重要程度因子,其值越大,表示启发函数在转移中的作用越大,即蚂蚁会以较大的概率转移到距离短的城市
    private double beta;
    //城市数量
    private int cityNum;
    //蚂蚁的起始城市
    private int firstCity;
    //蚂蚁当前所在城市
    private int currentCity;
    public Ant(double[][] distanceMatrix, double alpha, double beta) {
        this.distanceMatrix = distanceMatrix;
        this.alpha = alpha;
        this.beta = beta;
        this.cityNum = distanceMatrix[0].length;
        this.unVisitedCities = new LinkedHashSet<>();
        this.sequence = new ArrayList<>();
        this.delta = new double[cityNum][cityNum];
    }
    /**
     * 初始化蚂蚁,随机选择起始位置
     */
    public void initAntMessage() {
        this.unVisitedCities.clear();
        this.sequence.clear();
        //初始化信息素变化矩阵为0
        for (int i = 0; i < cityNum; i++) {
            for (int j = 0; j < cityNum; j++) {
                this.delta[i][j] = 0;
            }
            this.unVisitedCities.add(i);
        }
        //随机挑选一个城市作为起始城市
        this.firstCity = new Random().nextInt(cityNum);
        //未访问城市集合中移除起始城市
        this.unVisitedCities.remove(this.firstCity);
        //将起始城市添加至序列中
        this.sequence.add(this.firstCity);
        //设置蚂蚁当前所在城市为起始城市
        this.currentCity = firstCity;
    }
    /**
     * 结合蚂蚁当前所在城市和信息素矩阵选择蚂蚁下一个要访问的城市
     *
     * @param pheromone 信息素矩阵
     */
    public void selectNextCity(double[][] pheromone) {
        计算从当前城市去往未访问城市的概率
        double[] p = new double[this.cityNum];
        //分母
        double denominator = 0;
        //计算分母部分
        for (Integer cityIndex : this.unVisitedCities) {
            denominator += Math.pow(pheromone[this.currentCity][cityIndex], alpha) * Math.pow(1.0 / distanceMatrix[this.currentCity][cityIndex], beta);
        }
        //计算去未访问的城市的概率矩阵,去过的城市概率为0,不用设置
        for (Integer cityIndex : this.unVisitedCities) {
            //除以分母,求概率,同时也是归一化的一种方式
            p[cityIndex] = (Math.pow(pheromone[this.currentCity][cityIndex], alpha) * Math.pow(1.0 / distanceMatrix[this.currentCity][cityIndex], beta)) / denominator;
        }
        轮盘赌选择下一个城市
        //指针指向的概率
        double selectP = new Random().nextDouble();
        //下一个要访问的城市
        int nextCity = -1;
        //存储最后一个未访问的城市,防止浮点数精度原因,没有选择到城市
        int lastAllowedCity = -1;
        double sum = 0;
        for (Integer city : this.unVisitedCities) {
            lastAllowedCity = city;
            sum += p[city];
            //找到指针指向的城市,退出循环
            if (sum >= selectP) {
                nextCity = city;
                break;
            }
        }
        //当没有选择到城市时,选择未访问城市中的最后一个城市
        nextCity = nextCity == -1 ? lastAllowedCity : nextCity;
        //从允许选择的城市中去除selectCity
        this.unVisitedCities.remove(nextCity);
        //在sequence中添加nextCity
        this.sequence.add(nextCity);
        //将当前城市改为选择的城市
        this.currentCity = nextCity;
    }
    /**
     * 计算路径长度
     *
     * @return 路径长度
     */
    private double getObjectValue() {
        double objectValue = 0;
        //sequence最终样式:起始城市,城市1,城市2,... ,结尾城市,起始城市
        //this.sequence.size() - 1的原因,两点之间有一段距离,三点之间有两端距离
        for (int i = 0; i < this.sequence.size() - 1; i++) {
            objectValue += distanceMatrix[this.sequence.get(i)][this.sequence.get(i + 1)];
        }
        return objectValue;
    }
    public List<Integer> getSequence() {
        return sequence;
    }
    public void setSequence(List<Integer> sequence) {
        this.sequence = sequence;
    }
    public LinkedHashSet<Integer> getUnVisitedCities() {
        return unVisitedCities;
    }
    public void setUnVisitedCities(LinkedHashSet<Integer> unVisitedCities) {
        this.unVisitedCities = unVisitedCities;
    }
    public double[][] getDelta() {
        return delta;
    }
    public void setDelta(double[][] delta) {
        this.delta = delta;
    }
    public double[][] getDistanceMatrix() {
        return distanceMatrix;
    }
    public void setDistanceMatrix(double[][] distanceMatrix) {
        this.distanceMatrix = distanceMatrix;
    }
    public double getAlpha() {
        return alpha;
    }
    public void setAlpha(double alpha) {
        this.alpha = alpha;
    }
    public double getBeta() {
        return beta;
    }
    public void setBeta(float beta) {
        this.beta = beta;
    }
    public double getBestObjectValue() {
        return this.getObjectValue();
    }
    public int getCityNum() {
        return cityNum;
    }
    public void setCityNum(int cityNum) {
        this.cityNum = cityNum;
    }
    public int getFirstCity() {
        return firstCity;
    }
    public void setFirstCity(int firstCity) {
        this.firstCity = firstCity;
    }
    public int getCurrentCity() {
        return currentCity;
    }
    public void setCurrentCity(int currentCity) {
        this.currentCity = currentCity;
    }
}


蚁群算法

package com.dam.heuristic.aco.test;
import java.util.Arrays;
/**
 * 蚁群算法
 */
public class AcoApi {
    //蚂蚁数组
    private Ant[] antArr;
    //蚂蚁数量
    private int antNum;
    //城市数量
    private int cityNum;
    //迭代次数
    private int MAX_GEN;
    //信息素矩阵
    private double[][] pheromone;
    //最短回路长度
    private double bestObjectValue;
    //最佳路径
    private int[] bestSequence;
    //信息素挥发程度参数
    private double rho;
    public AcoApi(int antNum, int MAX_GEN, double alpha, double beta, double rho, double[][] distanceMatrix) {
        this.antNum = antNum;
        this.cityNum = distanceMatrix[0].length;
        this.MAX_GEN = MAX_GEN;
        this.rho = rho;
        //初始化信息素矩阵
        this.pheromone = new double[this.cityNum][this.cityNum];
        for (int i = 0; i < this.cityNum; i++) {
            for (int j = 0; j < this.cityNum; j++) {
                this.pheromone[i][j] = 0.1f; //初始化为0.1
            }
        }
        //初始化最优路径长度
        bestObjectValue = Integer.MAX_VALUE;
        //初始化最优序列
        bestSequence = new int[cityNum];
        //随机放置蚂蚁
        this.antArr =new Ant[antNum];
        for (int i = 0; i < antNum; i++) {
            this.antArr[i] = new Ant(distanceMatrix, alpha, beta);
            this.antArr[i].initAntMessage();
        }
    }
    public void solve() {
        long startTime = System.currentTimeMillis();
        //迭代MAX_GEN次
        for (int t = 0; t < this.MAX_GEN; t++) {
            //让所有蚂蚁都从自己的起点出发,完整走一个回路
            for (int i = 0; i < this.antNum; i++) {
                //让第i只蚂蚁走完所有城市,形成一个回路,j从1开始是因为蚂蚁本身已在起点城市
                for (int j = 1; j < this.cityNum; j++) {
                    this.antArr[i].selectNextCity(this.pheromone);
                }
                //把这只蚂蚁起始城市加入序列中
                this.antArr[i].getSequence().add(this.antArr[i].getFirstCity());
                //查看蚂蚁i所走的路径距离是否比当前最优解更好
                if (this.antArr[i].getBestObjectValue() < this.bestObjectValue) {
                    //更新最优解
                    this.bestObjectValue = this.antArr[i].getBestObjectValue();
                    for (int j = 0; j < this.cityNum; j++) {
                        this.bestSequence[j] = this.antArr[i].getSequence().get(j);
                    }
                    System.out.println("----------------------------------------------------------------------------------------------------------------");
                    System.out.println("当前代数:" + t);
                    System.out.println("当前最优解为:" + bestObjectValue);
                    System.out.println("当前计算时间为:" + (System.currentTimeMillis() - startTime) + "ms");
                    System.out.println("----------------------------------------------------------------------------------------------------------------");
                }
                //更新这只蚂蚁的信息数变化矩阵,对称矩阵
                for (int j = 0; j < this.cityNum; j++) {
                    this.antArr[i].getDelta()[this.antArr[i].getSequence().get(j)][this.antArr[i].getSequence().get(j + 1)]
                            = (1.0 / this.antArr[i].getBestObjectValue());
                    this.antArr[i].getDelta()[this.antArr[i].getSequence().get(j + 1)][this.antArr[i].getSequence().get(j)]
                            = (1.0 / this.antArr[i].getBestObjectValue());
                }
            }
            //更新信息素
            this.updatePheromone();
            //将蚂蚁放到不同的位置,重新初始化蚂蚁
            for (int i = 0; i < this.antNum; i++) {
                this.antArr[i].initAntMessage();
            }
        }
        System.out.println("最优解:"+this.bestObjectValue);
        System.out.println("最优序列:"+ Arrays.toString(this.bestSequence));
        System.out.println("计算时间:"+(System.currentTimeMillis()-startTime)+"ms");
    }
    /**
     * 更新信息素
     */
    private void updatePheromone() {
        //信息素挥发
        for (int i = 0; i < this.cityNum; i++) {
            for (int j = 0; j < this.cityNum; j++) {
                this.pheromone[i][j] = this.pheromone[i][j] * (1 - this.rho);
            }
        }
        //信息素更新
        for (int i = 0; i < this.cityNum; i++) {
            for (int j = 0; j < this.cityNum; j++) {
                for (int k = 0; k < this.antNum; k++) {
                    this.pheromone[i][j] += this.antArr[k].getDelta()[i][j];
                }
            }
        }
    }
}


测试

package com.dam.heuristic.aco.test;
import com.dam.heuristic.aco.csdn.Aco;
import com.dam.heuristic.ts.test.TsApi;
import java.io.File;
import java.io.FileInputStream;
public class AcoMainRun {
    public static void main(String[] args) throws Exception {
        声明变量
        //距离矩阵,可以直接获取任意两个编号城市的距离
        double[][] distanceMatrix;
        读取数据
        String data = read(new File("src/main/java/com/data/tsp/att48.txt"), "GBK");
        String[] cityDataArr = data.split("\n");
        //初始化数组
        distanceMatrix = new double[cityDataArr.length][cityDataArr.length];
        for (int i = 0; i < cityDataArr.length; i++) {
            String[] city1Arr = cityDataArr[i].split(" ");
            int cityOne = Integer.valueOf(city1Arr[0]);
            for (int j = 0; j < i; j++) {
                String[] city2Arr = cityDataArr[j].split(" ");
                int cityTwo = Integer.valueOf(city2Arr[0]);
                if (cityOne == cityTwo) {
                    distanceMatrix[cityOne - 1][cityTwo - 1] = 0;
                } else {
                    distanceMatrix[cityOne - 1][cityTwo - 1] = getDistance(Double.valueOf(city1Arr[1]), Double.valueOf(city1Arr[2]), Double.valueOf(city2Arr[1]), Double.valueOf(city2Arr[2]));
                    //对称赋值
                    distanceMatrix[cityTwo - 1][cityOne - 1] = distanceMatrix[cityOne - 1][cityTwo - 1];
                }
            }
        }
     /*   System.out.println("输出距离矩阵-------------------------------------------------------------------");
        for (double[] matrix : distanceMatrix) {
            System.out.println(Arrays.toString(matrix));
        }*/
        AcoApi acoApi = new AcoApi(15,500, 1.0,5.0, 0.5, distanceMatrix);
        acoApi.solve();
    }
    /**
     * 给定两个城市坐标,获取两个城市的直线距离
     *
     * @param x1
     * @param y1
     * @param x2
     * @param y2
     * @return
     */
    private static double getDistance(double x1, double y1, double x2, double y2) {
        return Math.sqrt((Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))/10);
    }
    private static String read(File f, String charset) throws Exception {
        FileInputStream fstream = new FileInputStream(f);
        try {
            int fileSize = (int) f.length();
            if (fileSize > 1024 * 512) {
                throw new Exception("File too large to read! size=" + fileSize);
            }
            byte[] buffer = new byte[fileSize];
            fstream.read(buffer);
            return new String(buffer, charset);
        } finally {
            try {
                fstream.close();
            } catch (Exception e) {
            }
        }
    }
}


最优解:11099.299942928516
最优序列:[28, 1, 25, 3, 34, 44, 23, 9, 41, 4, 47, 38, 31, 20, 12, 24, 13, 22, 10, 11, 14, 39, 8, 0, 7, 37, 30, 43, 17, 6, 27, 5, 36, 18, 26, 42, 16, 29, 35, 45, 32, 19, 46, 33, 2, 21, 15, 40]
计算时间:1621ms
目录
相关文章
|
17天前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
50 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
18天前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
29 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
19天前
|
算法 搜索推荐 Java
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。
66 0
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
|
22天前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
50 2
|
19天前
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
48 0
|
27天前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
15 0
|
3月前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
59 2
|
3月前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
6月前
|
Java
【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字
【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字
40 0
|
Java 数据安全/隐私保护 C++
Java - 注释、标识符、关键字
Java - 注释、标识符、关键字
112 0
Java - 注释、标识符、关键字