Задание №18 — Задачи на динамику для таблиц
Квадрат разлинован на N × N клеток (1 < N < 17). Исполнитель Робот может перемещаться по клеткам, выполняя за одно перемещение одну из двух команд: вправо или вниз. По команде вправо Робот перемещается в соседнюю правую клетку, по команде вниз — в соседнюю нижнюю. При попытке выхода за границу квадрата Робот разрушается. Перед каждым запуском Робота в каждой клетке квадрата лежит монета достоинством от 1 до 100. Посетив клетку, Робот забирает монету с собой; это также относится к начальной и конечной клетке маршрута Робота.
Определите максимальную и минимальную денежную сумму, которую может собрать Робот, пройдя из левой верхней клетки в правую нижнюю. В ответ запишите два числа друг за другом без разделительных знаков — сначала максимальную сумму, затем минимальную. Исходные данные представляют собой электронную таблицу размером N × N, каждая ячейка которой соответствует клетке квадрата.
Пример входных данных:
| 1 | 8 | 8 | 4 |
| 10 | 1 | 1 | 3 |
| 1 | 3 | 12 | 2 |
| 2 | 3 | 5 | 6 |
Для указанных входных данных ответом должна быть пара чисел:
| 41 | 22 |
Правильный ответ
1204 502
Пояснение
Решение:
Робот ходит только вправо и вниз, поэтому в любую клетку он приходит либо сверху, либо слева и ни одной клетки не проходит дважды. Значит, работает динамическое программирование: для каждой клетки достаточно хранить максимальную и минимальную суммы, которые можно накопить, дойдя до неё из левой верхней клетки.
Пусть — номинал монеты в клетке, и — максимальная и минимальная накопленные суммы. Тогда и , причём соседняя клетка учитывается только тогда, когда между ней и текущей нет стены. Для левой верхней клетки .
В этом варианте внутренних стен нет: Робот ограничен только границами квадрата. Поле в приложенном файле имеет размер , поэтому пересчёт идёт по обычным формулам, без дополнительных проверок.
Скопируем содержимое таблицы в текстовый файл 18.txt (числа разделены пробелами или знаками табуляции) и обработаем его программой.
f = open('18.txt')
a = [[int(x) for x in s.split()] for s in f]
N = len(a)
# внутренних стен нет
def wall_down(i, j):
return False
def wall_right(i, j):
return False
MX = [[0] * N for i in range(N)] # максимум, накопленный к клетке
MN = [[0] * N for i in range(N)] # минимум
for i in range(N):
for j in range(N):
if i == 0 and j == 0:
MX[i][j] = MN[i][j] = a[0][0]
continue
v = []
if i > 0 and not wall_down(i - 1, j):
v.append((MX[i - 1][j], MN[i - 1][j]))
if j > 0 and not wall_right(i, j - 1):
v.append((MX[i][j - 1], MN[i][j - 1]))
MX[i][j] = max(x for x, y in v) + a[i][j]
MN[i][j] = min(y for x, y in v) + a[i][j]
print(MX[N - 1][N - 1], MN[N - 1][N - 1])
Программа выводит 1204 502: максимальная сумма равна 1204, минимальная — 502. По условию сначала записывается максимальная сумма, затем минимальная.
Ответ: 1204 502