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

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

代码

package com.dam.heuristic.sa.test;
import java.util.Arrays;
import java.util.Random;
/**
 * 模拟退火
 */
public class SaApi {
    //序列长度
    private int sequenceLen;
    //初始温度
    private double startT;
    //结束温度
    private double endT;
    //每个温度的迭代次数
    private int timeInPerTemperature;
    //公式中的常数k
    private double k;
    //降温系数
    private double coolingCoefficient;
    //距离矩阵
    private double[][] distanceMatrix;
    /**
     * 构造函数,用于创建对象
     */
    public SaApi(double startT, double endT, int timeInPerTemperature, double k, double coolingCoefficient, double[][] distanceMatrix) {
        this.sequenceLen = distanceMatrix[0].length;
        this.startT = startT;
        this.endT = endT;
        this.timeInPerTemperature = timeInPerTemperature;
        this.k = k;
        this.coolingCoefficient = coolingCoefficient;
        this.distanceMatrix = distanceMatrix;
    }
    /**
     * 模拟退火算法接口
     */
    public void solve() {
        定义变量
        long startTime = System.currentTimeMillis();
        //当前温度
        double curT = this.startT;
        ///最优解
        //最优温度
        double bestT = this.startT;
        //序列
        int[] localSequence = new int[this.sequenceLen];
        //最优序列
        int[] bestSequence;
        //存储求得最优解的时间
        long bestTime = 0;
        //最优序列对应的目标函数值
        double bestObjectValue = 0;
        //上一序列的目标函数值
        double lastObjectValue = Double.MAX_VALUE;
        ///对象
        Random random = new Random();
        生成初始序列
        this.generateInitialSequence(localSequence);
        //初始化bestSequence,刚开始的最优序列为初始序列
        bestSequence = localSequence.clone();
        bestObjectValue = this.getObjectValue(bestSequence);
//        System.out.println("初始序列:" + Arrays.toString(bestSequence));
//        System.out.println("初始目标函数值:" + bestObjectValue);
        对序列进行迭代优化
        while (curT > this.endT) {
//            System.out.println("当前温度:" + curT + ",--------------------------------------------------------------");
            for (int i = 0; i < this.timeInPerTemperature; i++) {
                int[] tempSequence = this.generateNewSequence(localSequence);
                double tempObjectValue = this.getObjectValue(tempSequence);
                double de = tempObjectValue - lastObjectValue;
//                System.out.println("温度:" + bestT);
                if (de < 0) {
                    localSequence = tempSequence.clone();
                    lastObjectValue = tempObjectValue;
                    if (tempObjectValue<bestObjectValue){
                        //更新最优解
                        bestT = curT;
                        bestObjectValue = tempObjectValue;
                        bestSequence = tempSequence.clone();
//                    bestTime = (System.currentTimeMillis() - startTime);
//                        System.out.println("找到更优解:" + bestObjectValue + ",计算时间:" + bestTime + "ms");
                    }
                } else {
                    double p = Math.exp(-de / (this.k * curT));
                    if (p > random.nextDouble()) {
//                        System.out.println("当前接受差解为:" + tempObjectValue);
                        //替换序列
                        localSequence = tempSequence.clone();
                        lastObjectValue = tempObjectValue;
                    } else {
//                        System.out.println("不接受");
                    }
                }
            }
            curT *= this.coolingCoefficient;
        }
        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;
    }
}

模拟退火过程


测试

package com.dam.heuristic.sa.test;
import com.dam.heuristic.sa.improve.ImproveSaApi;
import java.io.File;
import java.io.FileInputStream;
public class SAMainRun {
    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));
        }*/
        System.out.println("saApi求解----------------------------------------------------------------------------");
        SaApi saApi = new SaApi(100000, 1e-8, 3000, 10000.0, 0.98, distanceMatrix);
        saApi.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) {
            }
        }
    }
}


saApi求解----------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
最佳温度:0.003086887433472753
最优目标函数值:11085.716110897114
最优解对应序列:[3, 25, 41, 1, 28, 4, 47, 33, 40, 15, 21, 39, 45, 35, 29, 42, 16, 26, 18, 36, 5, 27, 6, 17, 43, 30, 37, 8, 7, 0, 2, 22, 10, 11, 14, 32, 19, 46, 20, 12, 13, 24, 38, 31, 23, 9, 44, 34]
求解时间:1944ms
Process finished with exit code 0
目录
相关文章
|
1月前
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
2天前
|
算法
基于电导增量MPPT控制算法的光伏发电系统simulink建模与仿真
本课题基于电导增量MPPT控制算法,使用MATLAB2022a的Simulink进行光伏发电系统的建模与仿真,输出系统电流、电压及功率。电导增量调制(IC)算法通过检测电压和电流变化率,实时调整光伏阵列工作点,确保其在不同光照和温度条件下始终处于最大功率输出状态。仿真结果展示了该算法的有效性,并结合PWM技术调节逆变流器占空比,提高系统效率和稳定性。
|
12天前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
25天前
|
存储 人工智能 算法
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
|
26天前
|
算法 安全 Java
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
66 16
|
1月前
|
运维 监控 算法
企业局域网监控软件中 Java 优先队列算法的核心优势
企业局域网监控软件是数字化时代企业网络安全与高效运营的基石,犹如一位洞察秋毫的卫士。通过Java实现的优先队列算法,它能依据事件优先级排序,确保关键网络事件如异常流量、数据泄露等被优先处理,保障系统稳定与安全。代码示例展示了如何定义网络事件类并使用PriorityQueue处理高优先级事件,尤其在面对疑似风险时迅速启动应急措施。这一核心技术助力企业在复杂网络环境中稳健前行,护航业务腾飞。
65 32
|
29天前
|
算法 Java API
Java 方法注释:规范、实用和高质量的写法
本文深入探讨了如何编写高质量的 Java 方法注释
50 11
|
1月前
|
存储 监控 算法
剖析基于Java算法驱动的智能局域网管控之道
本文探讨了基于Java语言的局域网控制方案,结合链表数据结构与令牌桶算法,解决设备管理和流量调度难题。通过链表灵活存储网络设备信息,实现高效设备管理;令牌桶算法则精准控制流量,确保网络平稳运行。二者相辅相成,为校园、企业等局域网提供稳固高效的控制体系,保障业务连续性和数据安全。
|
29天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
61 6