Довольно простой подход к трехмерному динамическому c программированию заключается в следующем:
def dist(a,b): # gets distance between chars a and b
y1,x1 = a/6,a%6
y2,x2 = b/6,b%6
return abs(y1-y2)+abs(x1-x2)
def solve(s):
N = len(s)
dp = [[[float('inf') for x in range(26)] for x in range(26)] for x in range(N+1)]
dp[0] = [[0 for x in range(26)] for x in range(26)]
for i in range(N):
cur = ord(s[i])-ord('A')
for j in range(26):
for k in range(26):
dp[i+1][j][cur] = min(dp[i+1][j][cur], dp[i][j][k] + dist(k,cur)) # move right finger
dp[i+1][cur][k] = min(dp[i+1][cur][k], dp[i][j][k] + dist(j,cur)) # move left finger
res = float('inf')
for i in dp[N]:
res = min(res,min(i))
return res
В функции solve
мы объявляем динамическую c таблицу программирования dp[N+1][26][26]
, и давайте хранить в ячейке dp[i][j][k]
минимальное расстояние, необходимое для ввода всех символов в строке до, но не включая i-го символа, с левым пальцем на j-й клавише и правым пальцем на k-тая клавиша.
Наш базовый случай - i = 0
, мы знаем, что требуется 0
общее расстояние, чтобы наши пальцы начинали где угодно, поэтому первый ряд полностью инициализируется с помощью 0
s. Затем происходит переход от всех возможных конфигураций двух пальцев к перемещению левого или правого пальца на новую клавишу. Если вы находитесь в состоянии dp[i][j][k]
, то после нажатия i-й клавиши (назовем ее cur
), если мы нажимаем эту новую клавишу левым пальцем, обновленное состояние будет dp[i+1][cur][k]
, поскольку левый палец перешел с j на cur
. Точно так же, если мы нажмем его правым пальцем, обновленное состояние будет dp[i+1][j][cur]
.
Наш окончательный ответ находится где-то в строке N+1
, где N
- длина строки , Мы просто берем минимум всех комбинаций левого и правого пальцев в этом ряду.
РЕДАКТИРОВАТЬ: Вот двумерное решение, которое я описал в комментариях:
def solve(s):
N = len(s)
dp = [[float('inf') for x in range(26)]for x in range(N)]
dp[0] = [0 for x in range(26)]
for i in range(1,N):
cur = ord(s[i])-ord('A')
lst = ord(s[i-1])-ord('A')
for j in range(26): # one finger currently on s[i-1], other finger on j
dp[i][j] = min(dp[i][j], dp[i-1][j] + dist(lst,cur)) # move first finger, so second finger remains on j
dp[i][lst] = min(dp[i][lst], dp[i-1][j] + dist(j,cur)) # move second finger, so second finger becomes the new "first finger"
# and now the old "first finger" becomes the new "second finger"
res = min(dp[N-1])
return res