【运筹优化】状态压缩动态规划算法求解TSP问题 + Java代码实现


一、测试数据

1 6734 1453
2 2233 10
3 5530 1424
4 401 841
5 3082 1644
6 7608 4458
7 7573 3716
8 7265 1268
9 6898 1885
10 1112 2049
11 5468 2606
12 5989 2873
13 4706 2674
14 4612 2035
15 6347 2683
16 6107 669
17 7611 5184
18 7462 3590
19 7732 4723
20 5900 3561

二、代码0(读取数据的函数)

    private static List<double[]> getLocationList() throws IOException {
    
    
        FileInputStream fis = new FileInputStream("这里改成数据的路径");
        List<double[]> locationList = new ArrayList<>();
        int len = 0;
        StringBuilder sb = new StringBuilder();
        while ((len=fis.read())!=-1){
    
    
            sb.append((char)len);
        }
        fis.close();
        String[] split = sb.toString().split("\n");
        for (String s : split) {
    
    
            String[] s1 = s.split(" ");
            double[] doubles = new double[]{
    
    Double.parseDouble(s1[1]),Double.parseDouble(s1[2])};
            locationList.add(doubles.clone());
        }
        return locationList;
    }

三、代码1(Map存储结果、无状态压缩优化)

public class DP_TSP_1 {
    
    

    // 城市坐标<[x,y]>
    List<double[]> locationList;
    // 距离矩阵
    double[][] distance;
    // 城市数量
    int cityNum;
    // 开始地点索引
    int startIndex;
    // dp Map
    HashMap<String, Double> dpMap;

    public DP_TSP_1(List<double[]> locationList) {
    
    
        this.locationList = locationList;
    }

    public void solve() {
    
    
        initVar();
        solver();
    }

    private void solver() {
    
    
        int[] Gh = new int[cityNum - 1];
        int j = 0;
        for (int i = 0; i < cityNum; i++) {
    
    
            if (i != j) {
    
    
                Gh[j++] = i;
            }
        }
        System.out.println("最短距离为:" + subProblem(startIndex, Gh));
    }

    private double subProblem(int firstIndex, int[] others) {
    
    
        String key = firstIndex + Arrays.toString(others);
        if (dpMap.containsKey(key)) {
    
    
            return dpMap.get(key);
        } else if (others == null || others.length == 0) {
    
    
            dpMap.put(key, distance[firstIndex][startIndex]);
            return distance[firstIndex][startIndex];
        } else {
    
    
            double min = Double.MAX_VALUE;
            for (int i = 0; i < others.length; i++) {
    
    
                int[] newOthers = new int[others.length - 1];
                int k = 0;
                for (int j = 0; j < others.length; j++) {
    
    
                    if (i != j) {
    
    
                        newOthers[k++] = others[j];
                    }
                }
                String curKey = others[i] + Arrays.toString(newOthers);
                double cur = distance[firstIndex][others[i]] + (dpMap.containsKey(curKey) ? dpMap.get(curKey) : subProblem(others[i], newOthers));
                min = Math.min(cur, min);
            }
            dpMap.put(key, min);
            return min;
        }
    }

    // 初始化变量
    public void initVar() {
    
    
        // dp Map
        dpMap = new HashMap<>();
        // 开始地点索引
        startIndex = 0;
        // 城市数量为点的数量
        cityNum = locationList.size();
        // 距离矩阵
        distance = new double[cityNum][cityNum];
        // 初始化距离矩阵
        for (int i = 0; i < distance.length; i++) {
    
    
            for (int j = i; j < distance[i].length; j++) {
    
    
                if (i == j) {
    
    
                    // 对角线为0
                    distance[i][j] = Double.MAX_VALUE;
                } else {
    
    
                    // 计算i到j的距离
                    distance[i][j] = getDistance(locationList.get(i), locationList.get(j));
                    distance[j][i] = distance[i][j];
                }
            }
        }
    }

    // 计算两点之间的距离(使用伪欧氏距离,可以减少计算量)
    public double getDistance(double[] place1, double[] place2) {
    
    
        // 伪欧氏距离在根号内除以了一个10
//        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)) / 10.0);
        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)));
    }

}

运行结果:

动态规划算法求解tsp问题:20个城市...
最短距离为:22960.87072754488
求解用时:25.625 s

四、代码2(Map存储结果+状态压缩优化)

public class DP_TSP_2 {
    
    

    // 城市坐标<[x,y]>
    List<double[]> locationList;
    // 距离矩阵
    double[][] distance;
    // 城市数量
    int cityNum;
    // 开始地点索引
    int startIndex;
    // dp Map
    HashMap<String, Double> dpMap;

    public DP_TSP_2(List<double[]> locationList) {
    
    
        this.locationList = locationList;
    }

    public void solve() {
    
    
        initVar();
        solver();
    }

    private void solver() {
    
    
        int othersFlag = 0;
        for (int i = 0; i < cityNum; i++) {
    
    
            if (i != startIndex) {
    
    
                othersFlag = othersFlag | (1 << i);
            }
        }
        System.out.println("最短距离为:" + subProblem(startIndex, othersFlag));
    }

    private double subProblem(int firstIndex, int othersFlag) {
    
    
        String key = firstIndex + "-" + othersFlag;
        if (dpMap.containsKey(key)) {
    
    
            return dpMap.get(key);
        } else if (othersFlag == 0) {
    
    
            dpMap.put(key, distance[firstIndex][startIndex]);
            return distance[firstIndex][startIndex];
        } else {
    
    
            double min = Double.MAX_VALUE;
            for (int i = 0; i < cityNum; i++) {
    
    
                if ((othersFlag & (1 << i)) == 0) {
    
    
                    continue;
                }
                int newOthersFlag = othersFlag ^ (1 << i);
                String curKey = i + "-" + newOthersFlag;
                double cur = distance[firstIndex][i] + (dpMap.containsKey(curKey) ? dpMap.get(curKey) : subProblem(i, newOthersFlag));
                min = Math.min(cur, min);
            }
            dpMap.put(key, min);
            return min;
        }
    }

    // 初始化变量
    public void initVar() {
    
    
        // 城市数量为点的数量
        cityNum = locationList.size();
        if (cityNum > 32) {
    
    
            throw new RuntimeException("城市数量大于32位,不能进行DP求解");
        }
        // dp Map
        dpMap = new HashMap<>();
        // 开始地点索引
        startIndex = 0;
        // 距离矩阵
        distance = new double[cityNum][cityNum];
        // 初始化距离矩阵
        for (int i = 0; i < distance.length; i++) {
    
    
            for (int j = i; j < distance[i].length; j++) {
    
    
                if (i == j) {
    
    
                    // 对角线为0
                    distance[i][j] = Double.MAX_VALUE;
                } else {
    
    
                    // 计算i到j的距离
                    distance[i][j] = getDistance(locationList.get(i), locationList.get(j));
                    distance[j][i] = distance[i][j];
                }
            }
        }
    }

    // 计算两点之间的距离(使用伪欧氏距离,可以减少计算量)
    public double getDistance(double[] place1, double[] place2) {
    
    
        // 伪欧氏距离在根号内除以了一个10
//        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)) / 10.0);
        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)));
    }

}

运行结果:

动态规划算法求解tsp问题:20个城市...
最短距离为:22960.87072754488
求解用时:11.207 s

五、代码3(二维数组存储结果+状态压缩优化)

public class DP_TSP_3 {
    
    

    // 城市坐标<[x,y]>
    List<double[]> locationList;
    // 距离矩阵
    double[][] distance;
    // 城市数量
    int cityNum;
    // 开始地点索引
    int startIndex;
    // dp Array
    Double[][] dp;

    public DP_TSP_3(List<double[]> locationList) {
    
    
        this.locationList = locationList;
    }

    public void solve() {
    
    
        initVar();
        solver();
    }

    private void solver() {
    
    
        int othersFlag = 0;
        for (int i = 0; i < cityNum; i++) {
    
    
            if (i != startIndex) {
    
    
                othersFlag = othersFlag | (1 << (cityNum - 1 - i));
            }
        }
        dp = new Double[cityNum][othersFlag + 1];
        System.out.println("最短距离为:" + subProblem(startIndex, othersFlag));
        List<Integer> bestPath = new ArrayList<>();
        bestPath.add(startIndex);
        System.out.println("最短路径:" + getBestPath(bestPath, startIndex, othersFlag));
    }

    private double subProblem(int firstIndex, int othersFlag) {
    
    
        if (dp[firstIndex][othersFlag] != null) {
    
    
            return dp[firstIndex][othersFlag];
        } else if (othersFlag == 0) {
    
    
            dp[firstIndex][othersFlag] = distance[firstIndex][startIndex];
            return distance[firstIndex][startIndex];
        } else {
    
    
            double min = Double.MAX_VALUE;
            for (int i = 0; i < cityNum; i++) {
    
    
                if ((othersFlag & (1 << (cityNum - 1 - i))) == 0) {
    
    
                    continue;
                }
                int newOthersFlag = othersFlag ^ (1 << (cityNum - 1 - i));
                double cur = distance[firstIndex][i] + (dp[i][newOthersFlag] != null ? dp[i][newOthersFlag] : subProblem(i, newOthersFlag));
                min = Math.min(cur, min);
            }
            dp[firstIndex][othersFlag] = min;
            return min;
        }
    }

    private List<Integer> getBestPath(List<Integer> path, int firstIndex, int othersFlag) {
    
    
        if (othersFlag == 0) {
    
    
            path.add(startIndex);
            return path;
        } else {
    
    
            double min = Double.MAX_VALUE;
            int minIndex = -1;
            for (int i = 0; i < cityNum; i++) {
    
    
                if ((othersFlag & (1 << (cityNum - 1 - i))) == 0) {
    
    
                    continue;
                }
                int newOthersFlag = othersFlag ^ (1 << (cityNum - 1 - i));
                double cur = distance[firstIndex][i] + dp[i][newOthersFlag];
                if (cur <= min - 1e-06) {
    
    
                    min = cur;
                    minIndex = i;
                }
            }
            path.add(minIndex);
            int newOthersFlag = othersFlag ^ (1 << (cityNum - 1 - minIndex));
            return getBestPath(path, minIndex, newOthersFlag);
        }
    }

    // 初始化变量
    public void initVar() {
    
    
        // 城市数量为点的数量
        cityNum = locationList.size();
        if (cityNum > 31) {
    
    
            throw new RuntimeException("城市数量大于31位,不能进行DP求解");
        }
        // 开始地点索引
        startIndex = 0;
        // 距离矩阵
        distance = new double[cityNum][cityNum];
        // 初始化距离矩阵
        for (int i = 0; i < distance.length; i++) {
    
    
            for (int j = i; j < distance[i].length; j++) {
    
    
                if (i == j) {
    
    
                    // 对角线为0
                    distance[i][j] = Double.MAX_VALUE;
                } else {
    
    
                    // 计算i到j的距离
                    distance[i][j] = getDistance(locationList.get(i), locationList.get(j));
                    distance[j][i] = distance[i][j];
                }
            }
        }
    }

    // 计算两点之间的距离(使用伪欧氏距离,可以减少计算量)
    public double getDistance(double[] place1, double[] place2) {
    
    
        // 伪欧氏距离在根号内除以了一个10
//        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)) / 10.0);
        return Math.sqrt((Math.pow(place1[0] - place2[0], 2) + Math.pow(place1[1] - place2[1], 2)));
    }

}

运行结果:

动态规划算法求解tsp问题:20个城市...
最短距离为:22960.87072754488
最短路径:[0, 7, 8, 14, 17, 6, 5, 18, 16, 19, 11, 10, 12, 13, 4, 9, 3, 1, 2, 15, 0]
求解用时:1.163 s

猜你喜欢

转载自blog.csdn.net/weixin_51545953/article/details/129879354