概要
硬核DP问题,本问题设计状态转移方程较为困难。
给定初始位置pos
为0
,速度speed
为1
的“汽车”,有两种指令A(Accelerate)
和R(Reverse)
可供使用:
A
指令可使汽车的位置变为pos + speed
,同时speed *= 2
;R
指令可重置汽车的速度为1
,且方向相反。(您可能会担忧速度为0
的情况,但这种情况并不存在)
现给出一个目标位置target
,求出到达此位置使用的最少的操作数目。
动态规划
状态定义如下:
令F[i]
表示到达位置i
所需要的最少操作数目。
状态转移方程的定义涉及到几种情况的讨论,首先定义好边界条件:
F[0] = 0
其次,设计状态转移方程时要考虑到3种情况,为了说明清楚这些情况,您需要在脑中描绘一根数轴。初始时,汽车处于原点位置,考虑汽车永远不进行R
操作,一直往前开的情况,很容易发现,进行n
次A
操作到达的位置为$2^n - 1$,假定目的地为t
,那么有
存在$n \in N$,使得$t = 2^n - 1$,那么此时的答案
F[t] = n
。一路往前开即使最优解,任何的倒车操作都是无用的。汽车开过了位置
t
,并从t
右侧开回到t
。这种情况下,要明白一个重要事实:
汽车一定会在刚刚开过
t
时执行R
操作反向,没有必要继续远离t
往前开。由于从位置$2^n - 1$能够反向回到$2^{n - 1}$且所需的步数与从$0$到$2^{n - 1} - 1$所需步数一致(可以参考这个例子,0->1->3->7->15->15->14->12->8,从15到8经过3步,从0到7也经过3步),因此若继续往前开,反向后经过一定的步数后必定会回到上个位置,因此往前开是徒增花费的无意义动作。
因此,这种情况下,可以得到下列状态转移方程:
F[i] = n + 1 + F[n - i]
其中,
n = ceil(log2(i))
,代表距离t
最近的右侧的能够全程加速开到的位置,开到后,执行反向操作R
耗费1点,之后以位置n
为原点,看作是一个从0
到位置n - i
的子问题。汽车未开过位置
t
,进行了反向操作。在这种情况下,汽车会在到达位置
t
之前至少进行两次R
操作,调整其位置。那么在这种情况下,可以得到下列状态转移方程:F[i] = j + k + 2 + F[i - (2^j - 2^k)]
其中,
j
表示第一段连续的A
操作的个数,k
表示第一次反向后倒退的A
操作的个数,2
表示两次反向操作,而后可以看作是从新位置到位置i
的一个子问题,其中新位置等于前进距离与倒退距离的差$(2^j - 1) - (2^k - 1)$。这里要注意j
和k
的取值范围,j
的范围是0 <= j < n
,因为当前情况下不得开过位置t
;k
的取值范围是0 <= k < j
,当k == 0
时代表原地重置速度,当k == j
时则相当于没开。
综上所述,可以得到状态及状态转移方程如下:
F[i]表示到达位置i所需要的最少操作数目
1 | F[0] = 0 |
未证明 情况3中j
可固定为n - 1
。