双调欧几里得旅行家问题

内容提要:

问题背景
问题分析
问题解决
复杂分析
附录代码

问题背景:
欧几里得旅行商问题是对平面给定的 n 个点确定一条连接各点的最短闭合路径旅程的问题。这个问题的一般形式是 NP 完全的,故其解需要 多项式 ( n^k ) 的时间。
J. L. Bentley 建议通过只考虑双调旅程来简化问题,这种旅程即为从左点开始,严格地从左到右直至最右点,然后严格地从右直至出发点。


分析准备:
排序
将点按 x 坐标使用快速排序 ( O(n log n ))
表示为 p1p2 pj

最优子结构
最短路径问题具有最优子结构:假设节点 u ≠ v ,这样任何从 u v 的路径 p 必定包含一个中间顶点,譬如 w (w 可以是 u v)
于是,可以将 u →p →v 分解为子路径 u →p1 w →p2 v 。显然, p 上边的数目等于 p1 上边的数目加上 p2 上边的数目。如果 p 是从 u v 最优路径,那么 p1 必定是从 u w 的一条最短路径。(cut-and-paste)
最优子结构
首先定义路径 p(i,j) (i <= j) ,对于路径 p(i,j) 来说,它包含的点为 p1p2 pj 。其中以 pi 点为起点, p(i,j) 表示从 pi 点开始走,一直向左走到 p1 然后从 p1 沿不同的路径向右走直到 pj
其次,定义数组 d[ i,j ] 表示 p(i,j) 路径上的最短 Bitonic 路线
题目所求为 d[ n,n ]
cut-and-paste 可证得最优子结构

递归求解
只有一个 点没有意义, d[1,1]
个点时 d[1,2]=| p_1p_2 |
一般 地:

d[i,j]=(d[i,j-1]+|p(j-1)pj|      i≤j

=min(1≤k<j-1){ d[k,j-1]+|pkpj| }  i=j

=|p1p2|                              i=1

d[n,n] = d[n-1,n] + |p(n-1)pn|


计算一个 最优解
采用自底向上的 方法,在计算过程中需要保存两个值,一个 d[ i,j ] 的值,第二个是要记录 p(i,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<d[j-1,j]
               then d[j-1,j] ←a
                   pre[j-1,j] ←k
d[n,n]=d[n-1,n]+|pn-1pn|
return d and pre


构造一个序列
我们定义一个如下的输出 序列:
从最右侧的 pn 输出,依次从右至左输出至 p1 ,然后从 p1 输出到 pn 。本题示例输出为 p7p6p4p3p1p2p5

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<j
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


时间复杂度分析:

QUICK-SORT : O(n logn )
EUCLIDEAN-TSP : O( n^2 )
PRINT-TOUR : O(n)
BITONIC PATH : O( n^2 )







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您解答算法导论第15章的双调欧得旅行商问题和整齐打印问题。 1. 双调欧得旅行商问题 双调欧得旅行商问题是指在平面上给定一些点,求一条简单闭合曲线,使得经过每个点恰好一次,且总路程最小。其中,欧几得距离是指两点之间的距离。 该问题可以通过分治算法进行求解,具体步骤如下: 1)将所有的点按照x坐标从小到大排序; 2)将所有的点分成两部分,分别求出每一部分的最小路径,分别记为d1和d2; 3)在两部分的点中,选择一个点p,使得p在上一部分的最后一个点,同时p在下一部分的第一个点; 4)以p为分界点,将所有点分成上下两部分,并分别按照y坐标从小到大排序; 5)分别计算上半部分和下半部分的最小路径,分别记为d3和d4; 6)最终结果为d1+d2+d3+d4。 2. 整齐打印 整齐打印问题是指将一段文本分成若干行,每行不超过给定的宽度,使得每一行的长度尽可能相等,同时在每行末尾添加空格,使得每行的末尾恰好是一个单词的末尾,且每行的空格数最小。 该问题可以通过动态规划算法进行求解,具体步骤如下: 1)定义一个cost数组,其中cost[i][j]表示将第i个单词到第j个单词放在一行的代价; 2)定义一个lc数组,其中lc[i][j]表示将第i个单词到第j个单词放在一行的空格数; 3)计算cost和lc数组,具体方法如下: - 对于任意的i<=j,将第i到第j个单词放在一行,计算该行的空格数; - 如果该行的长度超过给定的宽度,则该方案不可行,否则将该方案的代价和空格数存入cost和lc数组中。 4)定义一个dp数组,其中dp[i]表示将前i个单词分成若干行的最小代价; 5)动态规划求解dp数组,具体方法如下: - 对于任意的1<=i<=n,将前i个单词分成若干行,计算最小代价; - 设最后一行的单词范围为[j+1, i],则dp[i] = min(dp[j] + cost[j+1][i]),其中j的范围为0<=j<i。 6)最终结果为dp[n]。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值