Dynamic Programming:双调旅行商问题(旅行商的变种)的解法

来源:互联网 发布:json被截断 编辑:程序博客网 时间:2024/06/06 13:56

关于TSP问题,毫无疑问它是一个NPC的问题。至今无多项式时间的解法。

很有意思的是,有意者定义了一种新的旅行商问题,成为双调旅行商问题,问题描述如下:

将所有的点看作二维平面上的一个点,每个点的坐标分别为(x,y),要求最后的旅程是从最左点开始,严格地的、从左到右到达右节点,然后严格地按照从右到左直至出发点,在这种情况下,多项式的时间是可能的。

问题分析:

首先是要找到最优子问题的所在。由于上下两条路径的点是完全不相交的,这就意味着一条路径选定一些点之后,这些点讲不能再被考虑,因此这两部分不独立,所以不应该分开来考虑。不失一般性,我们可以假设 P1 总是比P2走的快。(这是很重要的假设。)

其次根据题目要求,路线的两个部分显然都是递增的,假设两路线为P1,P2,比如P1到达了i点,P2到达了j点,那么max{ i, j } 就已经确定了走法:

比如 i > j, 那么 i 之前的点已经走掉了,或者是被P1,或者是被P2;(因为即使i ,j 之间存在着没有被走的点,那么P2也会将这些点走完,因为P1和P2都是不可能回头的)。

类似地,i < j有同样的分析。

如果i == j,P1和P2中最后走的边是 (1,i)(2,i)...(i - 1,i).

基于上述描述,我们的子问题定义为如下的结构:

P[ i , j ] : 表示 P1走到了 i 点,P2走到了 j 点,并且  i  之前的所有的点已经都被走过了。(也就是说 j  现在是P2 走的最远的点。)


定义符号如下: D[i,j] 表示节点i到节点j的距离,(此处应该是欧式距离)

P[i,j] 表示节点i到节点j之间的走过的路径上的距离,(即路径上各个边的欧式距离)。


因此,我们的算法描述应该如下:

1     我们对所有的节点编号,按照x轴递增的顺序,依次为1,2,...,n

2   由于上述假设,i >= j 

     i == j :  这样的情况只可能发生在  i = j = 0 和  i = j = n 时,  P[ i  j ] =  P [ i ,  j-1]   +  D[ j - 1 ,  j  ] (此处前一步显然是由 P2 走的,且是从 j - 1  走到  j  的。否则违反了假设。)

    i  >  j  :   分为两种情况,

                  第一种就是 i  与 j 之间没有其他的点,那么   P [ i , j ] = min { P [ k ,  j ]  +  D[ k , i ] }  其中  1<= k <= j-1;

                  第二种是 i 和 j 之间有其他的点,那么  P[ i , j ]  = P [ i-1 , j ]  + D[ i-1 , i ]  ( 此处至今我想的还不是很透彻)  (现在的大致思路是如果P1 走到了 i  点,P2 走到的 j 点,那么前一步的状态可能是什么呢?由于前一步的 P [ i - 1 , j ] 已经求出,那么可以直接使用当前的最优值即可。)

 

因此,总共需要计算 n^2 个元素,每一个元素的计算的时间复杂度必须是常数 时间的,整个算法的时间复杂度才是 O(n^2) , 由于我们在选择的时候,在每一行只有在计算 i = j + 1 是的时间复杂度为 O( j - i ),  该行的元素至多为 j ,因此均摊的时间复杂度为O(1), 显然整个时间复杂度为O(n^2).



反思:这对我来说是一个很困难的DP的题目,首先我的子问题如果定义的不好,那么递推式就会写的很复杂;其次两个方向上的路径是相互制约的,因此很难找到独立的子问题。最后我的几个递推式想得还不是太明白。只有模糊的概念,但是理论上还是说的通。




原创粉丝点击