旅行商问题(TSP问题)

题目
TSP问题(旅行商问题)是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。
假设现在有四个城市,0,1,2,3,他们之间的代价如图一,可以存成二维表的形式
《旅行商问题(TSP问题)》 《旅行商问题(TSP问题)》
现在要从城市0出发,最后又回到0,期间1,2,3都必须并且只能经过一次,使代价最小。

分析
TSP问题是NP完全问题;
从初始点出发的周游路线一共有(n-1)!条,即等于除初始结点外的n-1个结点的排列数,因此旅行商问题是一个排列问题。通过枚举(n-1)!条周游路线,从中找出一条具有最小成本的周游路线的算法,其计算时间显然为O(n!)。

方法1:动态规划方法
动态规划可行性:设s, s1, s2, …, sp, s是从s出发的一条路径长度最短的简单回路,假设从s到下一个城市s1已经求出,则问题转化为求从s1到s的最短路径,显然s1, s2, …, sp, s一定构成一条从s1到s的最短路径,所以TSP问题是构成最优子结构性质的,用动态规划来求解也是合理的。
推倒动态规划方程:
假设从顶点s出发,令d(i, V’)表示从顶点i出发经过V’(是一个点的集合)中各个顶点一次且仅一次,最后回到出发点s的最短路径长度。
推导:(分情况来讨论)
①当V’为空集,那么d(i, V’),表示从i不经过任何点就回到s了,如上图的 城市3->城市0(0为起点城市)。此时d(i, V’)=Cis(就是 城市i 到 城市s 的距离)、
②如果V’不为空,那么就是对子问题的最优求解。你必须在V’这个城市集合中,尝试每一个,并求出最优解。
d(i, V’)=min{Cik + d(k, V’-{k})} 注:Cik表示你选择的城市和城市i的距离,d(k, V’-{k})是一个子问题。
综上所述,TSP问题的动态规划方程就出来了:
《旅行商问题(TSP问题)》

将d(i, V’)转换成二维表,d[i][j]

实现


public class Num7 {

    private static int[][] d;
    private static int[] bits;
    /** * @param args */
    public static void main(String[] args) {
         int[][] c={ 
                    {0,3,6,7}, 
                    {5,0,2,3}, 
                    {6,4,0,2}, 
                    {3,7,5,0} 
                }; 
         getMinCost(c);

    }

    /*动态规划 实现TSP问题 * * 用二进制表示集合(比如1100,表示在当前集合中:节点1、节点2不存在,节点3和节点4存在) * * 从上到下求,递归 */
    public static void getMinCost(int[][] a){
        int n=a.length;
        bits=new int[n];
        for(int i=0;i<n;i++){
            bits[i]=1<<i;
        }

        d=new int[1000][n];

        for(int i=0;i<d.length;i++){
            for(int j=0;j<d[0].length;j++){
                d[i][j]=-1;
            }
        }
        int t=1;
        for(int i=1;i<n;i++){  //初始化这些值:{1}->1 {2}->2 {3}-3
            d[t<<(i-1)][i]=a[0][i];
        }

        int res=Integer.MAX_VALUE;

        t=0;
         for(int i=1;i<n;i++){
                t=t<<1;
                t=t|1;
        }
        for(int i=1;i<n;i++){
            int r=getD(i,t,n,a);
            if(r+a[i][0]<res){
                res=r+a[i][0];
            }
        }


        System.out.println(res);
    }

    private static int getD(int i, int t,int n,int[][] a) {
        int min=Integer.MAX_VALUE;

        if(d[t][i]!=-1){
            return d[t][i];
        }

        t=t&(~bits[i-1]);

        for(int j=1;j<n;j++){
            int tt=t&bits[j-1];   //遍历每个集合中的节点
            if(tt>0){   
                int res=getD(j,t,n, a);
                if(res+a[j][i]<min){
                    min=res+a[j][i];
                }
            }
        }

        d[t][i]=min;
        return d[t][i];
    }

}
    原文作者:银行家问题
    原文地址: https://blog.csdn.net/bh_xiaoxinba/article/details/52490790
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞