旅行商问题(TSP问题)

题目
TSP问题(旅行商问题)是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次然后回到出发城市,并要求所走的路程最短。
假设现在有四个城市,0,1,2,3,他们之间的代价如图一,可以存成二维表的形式
旅行商问题(TSP问题)_第1张图片 旅行商问题(TSP问题)_第2张图片
现在要从城市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问题的动态规划方程就出来了:
这里写图片描述

将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;i1<new int[1000][n];

        for(int i=0;ifor(int j=0;j0].length;j++){
                d[i][j]=-1;
            }
        }
        int t=1;
        for(int i=1;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;i1;
                t=t|1;
        }
        for(int i=1;iint r=getD(i,t,n,a);
            if(r+a[i][0]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;jint tt=t&bits[j-1];   //遍历每个集合中的节点
            if(tt>0){   
                int res=getD(j,t,n, a);
                if(res+a[j][i]return d[t][i];
    }

}

你可能感兴趣的:(面试,动态规划)