数学建模常用算法:蚁群算法求解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
目录
相关文章
|
6月前
|
算法 IDE Java
Java 项目实战之实际代码实现与测试调试全过程详解
本文详细讲解了Java项目的实战开发流程,涵盖项目创建、代码实现(如计算器与汉诺塔问题)、单元测试(使用JUnit)及调试技巧(如断点调试与异常排查),帮助开发者掌握从编码到测试调试的完整技能,提升Java开发实战能力。
589 0
|
9月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
4月前
|
机器学习/深度学习 算法
采用蚁群算法对BP神经网络进行优化
使用蚁群算法来优化BP神经网络的权重和偏置,克服传统BP算法容易陷入局部极小值、收敛速度慢、对初始权重敏感等问题。
408 5
|
9月前
|
人工智能 算法 NoSQL
LRU算法的Java实现
LRU(Least Recently Used)算法用于淘汰最近最少使用的数据,常应用于内存管理策略中。在Redis中,通过`maxmemory-policy`配置实现不同淘汰策略,如`allkeys-lru`和`volatile-lru`等,采用采样方式近似LRU以优化性能。Java中可通过`LinkedHashMap`轻松实现LRUCache,利用其`accessOrder`特性和`removeEldestEntry`方法完成缓存淘汰逻辑,代码简洁高效。
367 0
|
4月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
11月前
|
缓存 监控 负载均衡
如何提升 API 性能:来自 Java 和测试开发者的优化建议
本文探讨了如何优化API响应时间,提升用户体验。通过缓存(如Redis/Memcached)、减少数据负载(REST过滤字段或GraphQL精确请求)、负载均衡(Nginx/AWS等工具)、数据压缩(Gzip/Brotli)、限流节流、监控性能(Apipost/New Relic等工具)、升级基础设施、减少第三方依赖、优化数据库查询及采用异步处理等方式,可显著提高API速度。快速响应的API不仅让用户满意,还能增强应用整体性能。
|
6月前
|
机器学习/深度学习 算法 机器人
基于蚁群优化算法的直流电机模糊PID控制(Matlab实现)
基于蚁群优化算法的直流电机模糊PID控制(Matlab实现)
178 0
|
7月前
|
机器学习/深度学习 存储 算法
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
本文系统研究了多智能体强化学习的算法性能与评估框架,选用井字棋和连珠四子作为基准环境,对比分析Q-learning、蒙特卡洛、Sarsa等表格方法在对抗场景中的表现。实验表明,表格方法在小规模状态空间(如井字棋)中可有效学习策略,但在大规模状态空间(如连珠四子)中因泛化能力不足而失效,揭示了向函数逼近技术演进的必要性。研究构建了标准化评估流程,明确了不同算法的适用边界,为理解强化学习的可扩展性问题提供了实证支持与理论参考。
380 0
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
|
7月前
|
安全 Java 测试技术
Java 项目实战中现代技术栈下代码实现与测试调试的完整流程
本文介绍基于Java 17和Spring技术栈的现代化项目开发实践。项目采用Gradle构建工具,实现模块化DDD分层架构,结合Spring WebFlux开发响应式API,并应用Record、Sealed Class等新特性。测试策略涵盖JUnit单元测试和Testcontainers集成测试,通过JFR和OpenTelemetry实现性能监控。部署阶段采用Docker容器化和Kubernetes编排,同时展示异步处理和反应式编程的性能优化。整套方案体现了现代Java开发的最佳实践,包括代码实现、测试调试
241 0
|
7月前
|
人工智能 Java 测试技术
Java or Python?测试开发工程师如何选择合适的编程语言?
测试工程师如何选择编程语言?Java 还是 Python?多位资深专家分享建议:Python 入门简单、开发效率高,适合新手及自动化测试;Java 生态成熟,适合大型项目和平台开发。建议结合公司技术栈、个人基础及发展方向选择。长远来看,两者兼通更佳,同时关注 Go 等新兴语言。快速学习与实践才是关键。