Algorithm 动态规划惰性号码拨号(skiena)

Algorithm 动态规划惰性号码拨号(skiena),algorithm,dynamic-programming,Algorithm,Dynamic Programming,我正在尝试解决以下练习(摘自《算法设计手册》) 我们希望用两个手指计算在标准按键电话上拨打给定n位数字的最慢方式。我们假设两个手指从*和#键开始,将手指从一个按钮移动到另一个按钮所需的力与它们之间的欧几里得距离成正比。设计一种算法,计算拨号方法,包括将手指移动到最小的总距离,其中k是键盘上不同键的数目(对于标准电话,k=16)。尝试使用O(nk^3)时间 首先,让d=d1.d2…dn为n位序列 我提出的算法使用两个二维(nxk)数组L,R和 - L[a][b]:min cost to type

我正在尝试解决以下练习(摘自《算法设计手册》)

我们希望用两个手指计算在标准按键电话上拨打给定n位数字的最慢方式。我们假设两个手指从*和#键开始,将手指从一个按钮移动到另一个按钮所需的力与它们之间的欧几里得距离成正比。设计一种算法,计算拨号方法,包括将手指移动到最小的总距离,其中k是键盘上不同键的数目(对于标准电话,k=16)。尝试使用O(nk^3)时间

首先,让
d=d1.d2…dn为n位序列

我提出的算法使用两个二维(nxk)数组L,R和

- L[a][b]:min cost to type the d[a]-digit with  the left finger and having
   the right finger at button b
 - R[a][b]:same thing but with right and left instead.
为了填充这两个数组,我使用了两个几乎相同的递归函数(因此,我只发布L的递归函数)

起初,

- L[a+1][b]=L[a][b]+cost_from_d[a]_to_d[a+1]
也就是说,我们将右手手指保持在按钮上,将左手手指从d[a]移动到d[a+1]

然后,如果b==d[a](即用右键拨打的最后一个数字),则也存在其他“适当”方式,通过保持右指在d[a]按钮上的原样并将左指从任何位置移动到d[a+1],用左手指键入d[a+1]

 - L[a+1][b]=min(L[a+1][b],min(R[a][c]+cost_from_c_to_d[a+1]),) 
对于这一点,我首先找到了最低成本,这样我们用左拨d[a+1],用右拨d[a]。然后我将其与上一个项目符号的值进行比较,并保持最小值

填充数组后,只需找到最小L/R[n][任意值]即可找到最小成本

对我来说,这个代码似乎是正确的。然而,考虑到时间复杂度只有O(nk)而不是O(nk^3),我肯定犯了一些错误


有人知道这些错误在哪里吗?

你对部分解函数(L和R)的定义看起来很合理。您的重复关系可能正确,也可能不正确。表达式很难理解。尝试整理它并扩展理由。你确定你考虑过所有的手指路径吗?上一个键可能是用任意一只手键入的

一个有趣的问题是:我喜欢对每个集合的元素使用连续的字母组(例如,I和j表示次,a和b表示键)。使算法更易于阅读


啊哈!您的重复关系错过了某些路径(同时移动两个手指)

定义:(与您的相同)

d[i]
作为要拨打的电话号码的第i个键

L(i,x)
定义为输入第一个i键的最小成本,左手指结束于键d[i],右手指结束于键x

定义
R(i,y)
为最小成本。。。右指结束于键d[i],左指结束于键y

恢复关系:

L(i+1, x) = min of all
使用左手手指键入上一个键的路径。右手手指可能在任意键w处

L(i, w) + dist(d[i], d[i+1]) + dist(w, x)
        # left distance      # right distance
用右手手指键入上一个键的路径。左手手指可能在任何键y处

R(i, y) + dist(y, d[i+1]) + dist(d[i], x)
          # left distance   # right distance
(类似关系适用于函数R)

那么我们为什么要同时考虑移动两个手指呢?假设三角形不等式,一个最佳刻度盘除了打字之外,不会移动手指。但我们需要它来计算我们的部分解


在回顾中,部分解函数的选择决定了算法。上面,我们不得不考虑在最优解中没有结束的路径。

观察:假设三角形不等式,存在一个最佳拨号方式,手指除了打字之外从不移动。证据:如果拨号时手指移动但不打字,我们可以通过“懒惰”并在需要打字时移动来降低(或保持不变)成本

所以


为j定义
L(i,j)
谢谢你的回复!我在复制rec函数时犯了一个错误,现在我已经更正了它,并试图让它更清晰一点。谢谢,这更清晰了。我想我看到了问题所在。编辑答案。谢谢!接得好:)我想我们快到了。这个递归关系给出了O(nk^2),对吗?
L(i+1, j) = 
L(i, j) + dist(d[i], d[i+1])
L(i+1, i) = min of all
R(i, k) + dist(d[k], d[i+1])    over all k < i