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

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

代码

package com.dam.heuristic.ts.test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
/**
 * 禁忌搜索
 */
public class TsApi {
    //当前已占用的禁忌表长度
    private int curUsedTabooLen;
    //禁忌表长度
    private int tabooTableLength;
    //序列长度
    private int sequenceLen;
    //最大的迭代次数
    private int maxGen;
    //每次搜索领域的个数
    private int neighbourNum;
    //距离矩阵
    private double[][] distanceMatrix;
    /**
     * 构造函数,用于创建对象
     *
     * @param tabooTableLength
     * @param maxGen
     * @param neighbourNum
     * @param distanceMatrix
     */
    public TsApi(int tabooTableLength, int maxGen, int neighbourNum, double[][] distanceMatrix) {
        this.curUsedTabooLen = 0;
        this.tabooTableLength = tabooTableLength;
        this.sequenceLen = distanceMatrix[0].length;
        this.maxGen = maxGen;
        this.neighbourNum = neighbourNum;
        this.distanceMatrix = distanceMatrix;
    }
    /**
     * 禁忌搜素算法接口
     */
    public void solve() {
        定义变量
        long startTime = System.currentTimeMillis();
        //禁忌表
        int[][] tabooTable = new int[this.tabooTableLength][this.sequenceLen];//禁忌表
        //代数
        int t = 0;
        ///最优解
        //最优代数
        int bestT = 0;
        //序列
        int[] localSequence = new int[this.sequenceLen];
        //最优序列
        int[] bestSequence;
        //存储暂时序列
        int[] tempSequenceInNeighbour;
        //存储邻居中最好的序列对
        int[] bestSequenceInNeighbour = null;
        //存储求得最优解的时间
        long bestTime = 0;
        //最优序列对应的目标函数值
        double bestObjectValue = 0;
        生成初始序列
        this.generateInitialSequence(localSequence);
        //初始化bestSequence,刚开始的最优序列为初始序列
        bestSequence = localSequence.clone();
        bestObjectValue = this.getObjectValue(bestSequence);
        System.out.println("初始序列:" + Arrays.toString(bestSequence));
        System.out.println("初始目标函数值:" + bestObjectValue);
        对序列进行迭代优化
        while (t++ < this.maxGen) {
            //如果目标是最小化函数值,则初始化为Double.MAX_VALUE;反之,初始化为-Double.MAX_VALUE
            double bestObjectValueInNeighbour = Double.MAX_VALUE;
            //neighbourNum :搜索领域个数
            int i = 0;
            while (i < this.neighbourNum) {
                //产生一条新序列
                tempSequenceInNeighbour = this.generateNewSequence(localSequence);
                //判断是否在禁忌表中
                if (isSequenceAtTabooTable(tabooTable, tempSequenceInNeighbour) == false) {
                    //搜索到的邻居序列不在禁忌表中,i才加一
                    i++;
                    //不在禁忌表中时,执行下面的计算,获取tempSequence所对应的目标函数值
                    double tempObjectValue = this.getObjectValue(tempSequenceInNeighbour);
                    //更新最优解
                    if (tempObjectValue < bestObjectValueInNeighbour) {
                        bestObjectValueInNeighbour = tempObjectValue;
                        bestSequenceInNeighbour = tempSequenceInNeighbour.clone();
                    }
                }
            }
            //解禁忌表,LocalGh加入禁忌表
            this.addSequenceToTabooTable(tabooTable, bestSequenceInNeighbour);
            //接受邻居序列中的最优序列,让算法可以跳出局部最优
            localSequence = bestSequenceInNeighbour.clone();
//            System.out.println("当前最优邻居目标函数值:" + bestObjectValueInNeighbour);
//            System.out.println("当前最优邻居解:" + Arrays.toString(bestSequenceInNeighbour));
//            System.out.println("当前最优解为:" + bestObjectValue + ",求得最优解的时间:" + bestTime + "ms");
            //更新全局最优解
            if (bestObjectValueInNeighbour < bestObjectValue) {
                //更新最优代数
                bestT = t;
                //更新最优目标函数值
                bestObjectValue = bestObjectValueInNeighbour;
                //更新最优序列
                bestSequence = localSequence.clone();
                System.out.println("----------------------------------------------------------------------------------------------------------------");
                System.out.println("当前代数:" + t);
                System.out.println("当前最优解为:" + bestObjectValue);
                bestTime = (System.currentTimeMillis() - startTime);
                System.out.println("当前计算时间为:" + bestTime + "ms");
                System.out.println("----------------------------------------------------------------------------------------------------------------");
            }
//            System.out.println("当前计算时间为:" + (System.currentTimeMillis() - startTime) + "ms");
//            System.out.println("----------------------------------------------------------------------------------------------------------------");
        }
        System.out.println("最佳迭代次数:" + bestT);
        System.out.println("最优目标函数值:" + bestObjectValue);
        System.out.println("最优解对应序列:" + Arrays.toString(bestSequence));
        System.out.println("计算时间为:" + (System.currentTimeMillis() - startTime) + "ms");
    }
    /**
     * 生成初始序列
     */
    public void generateInitialSequence(int[] sequence) {
      /*  HashSet<Integer> sequenceSet = new HashSet<>();
        for (int i = 1; i < sequence.length; i++) {
            sequenceSet.add(i);
        }
        //贪婪算法获取初始序列,从城市0开始旅行,即城市0为起点城市
        sequence[0] = 0;
        //每次获取离当前城市最近的城市,并加入到sequence
        for (int i = 1; i < sequence.length; i++) {
            //寻找离i-1城市最近的城市,即确定第i个城市是哪个
            double smallDistance = Double.MAX_VALUE;
            int curCity = 0;
            for (Integer j : sequenceSet) {
                if (this.distanceMatrix[sequence[i - 1]][j] < smallDistance && j != sequence[i - 1] ) {
                    smallDistance = this.distanceMatrix[sequence[i - 1]][j];
                    curCity = j;
                }
            }
            sequence[i] = curCity;
            sequenceSet.remove(curCity);
        }*/
        for (int i = 0; i < sequence.length; i++) {
            sequence[i] = i;
        }
    }
    /**
     * 根据当前序列获取目标函数值
     *
     * @param sequence
     * @return
     */
    public double getObjectValue(int[] sequence) {
        double objectValue = 0;
        //计算从第0个城市到最后一个城市的路程
        for (int i = 0; i < sequence.length - 1; i++) {
            objectValue += this.distanceMatrix[sequence[i]][sequence[i + 1]];
        }
        //计算最后一个城市到第0个城市的路程
        objectValue += this.distanceMatrix[sequence[0]][sequence[sequence.length - 1]];
        return objectValue;
    }
    /**
     * 生产新序列
     *
     * @param sequence
     * @return
     */
    public int[] generateNewSequence(int[] sequence) {
        int[] sequenceClone = sequence.clone();
        //对序列中的元素进行打乱,即可产生新的序列
        Random random = new Random();
        int i = random.nextInt(sequence.length);
        int j = random.nextInt(sequence.length);
        while (i == j) {
            j = random.nextInt(sequence.length);
        }
        int temp = sequenceClone[i];
        sequenceClone[i] = sequenceClone[j];
        sequenceClone[j] = temp;
        return sequenceClone;
    }
    /**
     * 将序列加入禁忌表,如果禁忌表已满,根据先进先出的原则移除最早进入禁忌表的序列
     *
     * @param tabooTable
     * @param sequence
     */
    public void addSequenceToTabooTable(int[][] tabooTable, int[] sequence) {
        if (this.curUsedTabooLen < this.tabooTableLength) {
            //如果当前禁忌表还有空位,则直接加入即可
            for (int i = 0; i < sequence.length; i++) {
                tabooTable[this.curUsedTabooLen][i] = sequence[i];
            }
            this.curUsedTabooLen++;
        } else {
            //如果禁忌表已经满了,则移除第一个进表的路径,添加新的路径到禁忌表末尾
            //后面的禁忌编码全部向前移动一位,覆盖掉当前第一个禁忌编码
            for (int i = 0; i < tabooTable.length - 1; i++) {
                tabooTable[i] = tabooTable[i + 1].clone();
            }
            //将sequence加入到禁忌队列的最后
            for (int i = 0; i < sequence.length; i++) {
                tabooTable[tabooTable.length - 1][i] = sequence[i];
            }
        }
    }
    /**
     * 判断序列对是否存在于禁忌表中
     *
     * @param tabooTable
     * @param sequence
     * @return
     */
    public boolean isSequenceAtTabooTable(int[][] tabooTable, int[] sequence) {
        for (int i = 0; i < tabooTable.length; i++) {
            boolean flag = true;
            for (int j = 0; j < sequence.length; j++) {
                if (sequence[j] != tabooTable[i][j]) {
                    flag = false;
                    break;
                }
            }
            if (flag == true) {
                return true;
            }
        }
        return false;
    }
}


测试

package com.dam.heuristic.ts.test;
import java.io.File;
import java.io.FileInputStream;
public class TsMainRun {
    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));
        }*/
        TsApi TSApi = new TsApi(20, 100000, 100, distanceMatrix);
        TSApi.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) {
            }
        }
    }
}


最佳迭代次数:37144
最优目标函数值:10666.643562660376
最优解对应序列:[34, 44, 9, 23, 41, 4, 47, 38, 31, 20, 12, 24, 13, 22, 10, 46, 19, 11, 14, 32, 45, 35, 29, 42, 16, 26, 18, 36, 5, 27, 6, 17, 43, 30, 37, 8, 7, 0, 39, 2, 21, 15, 40, 33, 28, 1, 3, 25]
计算时间为:2375ms
目录
相关文章
|
机器学习/深度学习 人工智能 算法
当AI提示词遇见精密算法:TimeGuessr如何用数学魔法打造文化游戏新体验
TimeGuessr融合AI与历史文化,首创时间与空间双维度评分体系,结合分段惩罚、Haversine距离计算与加权算法,辅以连击、速度与完美奖励机制,实现公平且富挑战性的游戏体验。
|
存储 算法 数据可视化
基于禁忌搜索算法的TSP问题最优路径搜索matlab仿真
本程序基于禁忌搜索算法解决旅行商问题(TSP),旨在寻找访问多个城市的最短路径。使用 MATLAB 2022A 编写,包含城市坐标生成、路径优化及结果可视化功能。通过禁忌列表、禁忌长度与藐视准则等机制,提升搜索效率与解的质量,适用于物流配送、路径规划等场景。
|
人工智能 自然语言处理 测试技术
UGMathBench:评估语言模型数学推理能力的动态基准测试数据集
近年来,人工智能蓬勃发展,自然语言模型(LLM)进展显著。语言模型被广泛应用于自动翻译、智能客服、甚至医疗、金融、天气等领域。而研究者们仍在不断努力,致力于提高语言模型的规模和性能。随着语言模型的蓬勃发展,评估一个语言模型的性能变得越来越重要。其中一个重要的评估指标,就是衡量语言模型的推理能力和解决数学问题的能力。
724 38
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
机器学习/深度学习 存储 算法
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
本文系统研究了多智能体强化学习的算法性能与评估框架,选用井字棋和连珠四子作为基准环境,对比分析Q-learning、蒙特卡洛、Sarsa等表格方法在对抗场景中的表现。实验表明,表格方法在小规模状态空间(如井字棋)中可有效学习策略,但在大规模状态空间(如连珠四子)中因泛化能力不足而失效,揭示了向函数逼近技术演进的必要性。研究构建了标准化评估流程,明确了不同算法的适用边界,为理解强化学习的可扩展性问题提供了实证支持与理论参考。
729 0
强化学习算法基准测试:6种算法在多智能体环境中的表现实测
|
自然语言处理 算法 数据可视化
文本聚类效果差?5种主流算法性能测试帮你找到最佳方案
本文探讨了自然语言处理中句子嵌入的聚类技术,使用Billingsmoore数据集(925个英语句子)进行实验。通过生成句子嵌入向量并可视化分析,对比了K-Means、DBSCAN、HDBSCAN、凝聚型层次聚类和谱聚类等算法的表现。结果表明,K-Means适合已知聚类数量的场景,DBSCAN和HDBSCAN适用于未知聚类数量且存在异常值的情况,而谱聚类在句子嵌入领域表现不佳。最终建议根据数据特征和计算资源选择合适的算法以实现高质量聚类。
1137 0
文本聚类效果差?5种主流算法性能测试帮你找到最佳方案
|
Web App开发 测试技术 API
Playwright 测试报告中显示的标签和注释。
Playwright 测试报告中显示的标签和注释。
497 57
|
机器学习/深度学习 算法
扩散模型=进化算法!生物学大佬用数学揭示本质
在机器学习与生物学交叉领域,Tufts和Harvard大学研究人员揭示了扩散模型与进化算法的深刻联系。研究表明,扩散模型本质上是一种进化算法,通过逐步去噪生成数据点,类似于进化中的变异和选择机制。这一发现不仅在理论上具有重要意义,还提出了扩散进化方法,能够高效识别多解、处理高维复杂参数空间,并显著减少计算步骤,为图像生成、视频合成及神经网络优化等应用带来广泛潜力。论文地址:https://arxiv.org/pdf/2410.02543。
588 21
|
机器学习/深度学习 算法 PyTorch
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
软演员-评论家算法(Soft Actor-Critic, SAC)是深度强化学习领域的重要进展,基于最大熵框架优化策略,在探索与利用之间实现动态平衡。SAC通过双Q网络设计和自适应温度参数,提升了训练稳定性和样本效率。本文详细解析了SAC的数学原理、网络架构及PyTorch实现,涵盖演员网络的动作采样与对数概率计算、评论家网络的Q值估计及其损失函数,并介绍了完整的SAC智能体实现流程。SAC在连续动作空间中表现出色,具有高样本效率和稳定的训练过程,适合实际应用场景。
6720 7
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
|
算法 数据安全/隐私保护
基于SA模拟退火算法的多车辆TSP问题求解matlab仿真
本程序基于模拟退火(SA)算法求解多车辆旅行商问题(VRPMTS),使用MATLAB2022A实现。程序为三辆车规划最短路径,输出路线规划图与SA收敛曲线。核心代码通过迭代调整温度参数和接受概率,避免陷入局部最优,逐步逼近全局最优解。算法原理包括初始高温允许劣质解、逐步降温探索解空间,并结合邻居解生成方法优化路径。适用于物流配送、路径规划等领域,具有较高实用价值。