问题描述: 欧几里得旅行商问题是对平面上给定的n个点确定一条连接各点的最短闭合旅程的问题。如图(a)给出了一个7个点问题的解。这个问题的一般形式是NP完全的,故其解需要多于多项式的时间。
J.L. Bentley 建议通过只考虑双调旅程(bitonic tour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。下图(b)显示了同样的7个点的最短双调路线。在这种情况下,多项式的算法是可能的。事实上,存在确定的最优双调路线的O(n*n)时间的算法。
【动态规划】双调欧几里得旅行商问题
注:在一个单位栅格上显示的平面上的七个点。 a)最短闭合路线,长度大约是24.89。这个路线不是双调的。b)相同点的集合上的最短双调闭合路线。长度大约是25.58。
分析:
第一步,先按照每个节点的x坐标进行排序,从左到右标记为1,2,…,n。算法复杂度可以为O(n*log(n))。
第二步, 构建d[i][j]代表从i->1->j的最短路径长度。依据其定义,我们可以知道d[i][j] = d[j][i]。所以我们只计算i>j时的值。(为什么不考虑i==j时的值?因为对于d[n][n]最小的时候,图中必然不存在任意中间节点被走两次。)
构建W[i][j]代表从i到j的直接距离,坐标运算可得。
此时,考虑两种情况:
1 i>j+1时,此时i只可能和i-1节点相连。假设i可以与其它节点直接相连,那么由于i>j,i-1>j,j不可能成为两次路径中任意一次的端点。所以d[i][j] = d[i-1][j] + W[i][i-1]。
2 i==j+1时,此时i可能和所有小于i的节点直接相连。所以
第三步,初始值d[2][1] = W[2][1],两层循环计算d[i][j]。
for (int i = 3; i <= n; ++i)
for (int j = 1; j < i; ++j)
第四步,计算
所得d[n][n]即为最短双调路线的值。
一、问题介绍: 欧几里得旅行商问题是指:对于给定平面上的n个点,确定一条连接各点的、闭合的最短曲线这个问题是NP完全问题。Bitonic旅行路线问题是欧几里得旅行商问题的简化,这种旅行路线从最左边开始,严格地由左至右到最右边的点,然后再严格的由右至左回到开始点,求最短的路径长度。设计一个确定最优Bitonic旅行路线的O(n2)时间算法。假设不存在x坐标相同的点。 二、算法分析: 根据题意,首先将给定的n个点{p1,p2,…,pn}按x坐标的升序排列。在这里,我采用了快速排序算法,时间复杂度为O(nlogn)。对排好序的n个点进行分析很容易知道p1是最左侧的点,pn是最右侧的点。 下面刻画最优解的结构:首先定义路径Pi,j(i<=j),对于路径Pi,j来说,它包含的点为p1,p2,..pj。其中pi点为起始点,pi,j表示从pi点开始走,一直向左走到p1然后从p1点沿不同的路径向右走直到pj。其次,定义数组d[i,j]表示pi,j路径上的最小Bitonic路线。很容易看出,题目所求的即是d[n,n]。题目的最优解为d[n,n],此时,分析当pn点未连通的情况。因为点是排好序的,而且根据题意中的严格方向的要求,可以知道pn点必有一侧是跟pn-1点相连的,那么此时d[n-1,n]应该为pn-1,n的最优解。采用反证法,如果存在d’[n-1,n] 刻画好了最优解的结构,下面递归定义求解最优解的值:当只有一个点时,d[1,1]无意义。分析大于等于两个点的情况:当只有两个点时,很容易得到:d[1,2]=|p1p2|。对于路径Pi,j来说,如果pi不是pj的相邻点(i=j-1),d[i,j]=d[i,j-1]+|pj-1pj|;当i=j-1时,对于pj点来说,有一侧必与pi点相连,此时要判断pj点的另一侧与哪个点相连。根据最优解的结构,此时,定义整数k(1<=k 根据以上分析,可以得到d[n,n]的计算方法如下所示: d[1,2]=|p1p2| d[i,j]=d[i,j-1]+|pj-1pj|(i d[i,j]=min1<=k d[n,n]=d[n-1,n]+|pn-1pn| 接下来计算最优解的值,采用自底向上方法,在计算过程中,需要保存两个值,第一个是数组d[i,j]的值,第二个是要记录pi,j中pj点的相邻连接点的下标,用数组pre[i,j]表示。算法如下所示: Bitonic-tour(p) Quicksort{p1,p2,…pn} in order of increasing x-coordinate d[1,2]←|p1p2| for j←3 to n do for i←1 to j-2 do d[i,j] ← d[i,j-1]+|pj-1pj| pre[i,j]=j-1 d[j-1,j] ← ∞ for k←1 to j-2 do a←b[k,j-1]+|pkpj| if a then d[j-1,j] ←a pre[j-1,j] ←k d[n,n]=d[n-1,n]+|pn-1pn| return d and pre 最后,构造问题的最优解:根据题意,题目应该输出一个关于点集p的序列,这个序列即是题目中所求的旅游路线。在这里,我定义了输出的方式为从最右侧的点pn开始输出,依次输出左行方向的点直到p1,然后输出右行方向的点直到和pn相连的那个点为止。我们已知两个表d[i,j]和pre[i,j],输出的算法描述如下所示: Output-tour(p) print pn print pn-1 k←pre[n-1,n] Print-tour(pre,k,n-1) print pk
Print-tour(pre,i,j) if i then k←pre[i,j] print pk if k>1 then Print-tour(pre,i,k) else k←pre[j,i] if k>1 then Print-tour(pre,k,j) print pk 文章出处:http://blog.myspace.cn/e/404572333.htm 有感:关键点的理解:就是排序后p1,...,pn-1,pn 这n个点,组成的最优解中,由于要求是双调,所以pn一 定与pn-1这个点向连。所以就可以把一个求环的问题归约成一个求简单路径的问题。 这个简单路径就是pn-1严格递减向左走到p1,然后p1在严格递增向右走到pn.这个路径恰好用到p1到pn这n个 点。求解思想就是动态规划。 |