码迷,mamicode.com
首页 > 其他好文 > 详细

双调欧几里得旅行商问题

时间:2015-04-08 10:48:41      阅读:316      评论:0      收藏:0      [点我收藏+]

标签:

欧几里得旅行商问题是一个NP问题,问题描述:平面上n个点,确定一条连接各点的最短闭合旅程。

所以通常会简化为双调欧几里得问题来求一个近似解,借用下算法导论的图,如下所示

a)是一个最优欧几里得

b)为双调路线,从最左点开始严格向右至最右点

 

技术分享

 

通过动态规划求解,首先需要分析子问题:

双调路径为 i -> 00 -> j 最终结果为 i j 都为n-1;所以子问题为0 <= i < n; 0 <= j < n;

由于存在对称情况(bitonic[i][j] == bitonic[j][i]),所以仅考虑 i 小于 j 的情况 0 <= i < j < n; i 为左调起点,j 为右调终点;

 

求解时要考虑一下三种情况

1)当 i < j - 1 时 , 由于i为左调曲线起点,所以j - 1, j都在右调曲线上

     可以得出bitonic[i][j] = bitonic[i][j - 1] + distance[j - 1][j]

2)当 i == j - 1 时需要用到动态获取最小距离

     foreach (0 < k < i)

         bitonic[i][j] = min(bitonic[k][i] + distance[k][j])

3)当 i == j 时 由于线段p[j - 1][j]必定在左调或者右调线路上,

  所以最优线路bitonic[j - 1][j]或bitonic[j][j - 1]即为最优 bitonic[j][j]的前置路线

   因为bitonic[j - 1][j]和bitonic[j][j - 1]对称所以有:

      bitonic[j][j] = bitonic[j - 1][j] +  distance[j - 1][j]

 

分析好之后代码就很简单了:

package com.feinno.algorithmic.travelingsalesman;

import java.util.Arrays;

/**
 * 双调欧几里得算法
 * bitonic[i][j] 
 * 1)i为左调起点,j为右调终点
 * 2)0 <= i <= j <= n
 *    当 i < j - 1 时 , 由于i为左调曲线起点,所以j - 1, j都在右调曲线上
 *       可以得出bitonic[i][j] = bitonic[i][j - 1] + distance[j - 1][j]
 *    当 i == j - 1 时需要用到动态获取最小距离
 *       foreach (0 < k < i)
 *           bitonic[i][j] = min(bitonic[k][i] + distance[k][j])
 *    当 i == j 时 由于线段p[j - 1][j]必定在左调或者右调线路上,
 *    所以最优bitonic[j - 1][j]即为最优 bitonic[j][j]的前置路线
 *       bitonic[j][j] = bitonic[j - 1][j] +  distance[j - 1][j]
 * 
 * @author renzhaolong
 *
 */
public class BitonicTSP {
    
    /**
     * 两节点间距离
     */
    private double[][] distance;
    
    /**
     * 以i为左调起点,j为右调终点的双调距离
     */
    private double[][] bitonic;
    
    /**
     * 最优双调的前置节点
     */
    private Point[][] preposition;
    /**
     * 节点集合,按x坐标递增排序
     */
    private Point[] points;
    /**
     * 集合数量
     */
    int lenth = 0;
    
    /**
     * 按照约定计算双调欧几里得距离
     * @return
     */
    public double getBitonicResult() {
        bitonic[0][1] = getDistance(0, 1);

        for (int j = 2; j < lenth; j++) {
            // 第一种情况 i < j - 1
            for (int i = 0; i < j - 1; i++) {
                bitonic[i][j] = bitonic[i][j - 1] + getDistance(j - 1, j);
            }
            
            //第二种情况i = j - 1
            for (int k = 0; k < j - 1; k++) {
                double temp = bitonic[k][j - 1] + getDistance(k, j);
                if (temp < bitonic[j - 1][j]) {
                    bitonic[j - 1][j] = temp;
                    preposition[j - 1][j] = new Point(k, j - 1);
                }
            }
        }
        bitonic[lenth - 1][lenth - 1] = bitonic[lenth - 2][lenth - 1] + getDistance(lenth - 2, lenth - 1);
        return bitonic[lenth - 1][lenth - 1];
    }
    
    /**
     * 获取两个节点的距离
     * 如果缓存中存在数据直接返回,不存在计算并缓存
     * @param x1
     * @param x2
     * @return
     */
    private double getDistance(int x1, int x2) {
        if (x1 > x2) {
            x1 = x1 + x2;
            x2 = x1 - x2;
            x1 = x1 - x2;
        }
        if (distance[x1][x2] == -1) {
            distance[x1][x2] = points[x1].getDistance(points[x2]);
        }
        return distance[x1][x2]; 
    }
    
    public BitonicTSP(Point[] points) {
        lenth = points.length;
        Arrays.sort(points);
        this.points = points;
        distance = new double[lenth][lenth];
        bitonic = new double[lenth][lenth];
        preposition = new Point[lenth][lenth];
        for (int i = 0; i < lenth; i++) {
            for (int j = 0; j < lenth; j++) {
                distance[i][j] = -1;
                bitonic[i][j] = Double.MAX_VALUE;
            }
        }
    }
    
    public static void main(String[] args) {
        BitonicTSP tsp = new BitonicTSP(
                new Point[]{new Point(1, 1),
                        new Point(2, 7),
                        new Point(3, 4), 
                        new Point(6, 3),
                        new Point(7, 6), 
                        new Point(8, 2), 
                        new Point(9, 5)});
        System.out.println(tsp.getBitonicResult());
    }
}
package com.feinno.algorithmic.travelingsalesman;

public class Point implements Comparable<Point> {
    private int x;

    private int y;
    
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public double getDistance(Point other) {
        return Math.sqrt(Math.pow(getX() - other.getX(), 2) + Math.pow(getY() - other.getY(), 2));
    }
    
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public int compareTo(Point o) {
        return getX() - o.getX();
    }
}

 

双调欧几里得旅行商问题

标签:

原文地址:http://www.cnblogs.com/remagon/p/4401605.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!