Решение:
Робот ходит только вправо и вниз, поэтому в любую клетку он приходит либо сверху, либо слева и ни одной клетки не проходит дважды. Значит, работает динамическое программирование: для каждой клетки достаточно хранить максимальную и минимальную суммы, которые можно накопить, дойдя до неё из левой верхней клетки.
Пусть aij — номинал монеты в клетке, Mij и mij — максимальная и минимальная накопленные суммы. Тогда Mij=max(Mi−1,j,Mi,j−1)+aij и mij=min(mi−1,j,mi,j−1)+aij, причём соседняя клетка учитывается только тогда, когда между ней и текущей нет стены. Для левой верхней клетки M11=m11=a11.
Отличие этой задачи в том, что маршрут заканчивается не обязательно в правой нижней клетке: конечной является любая клетка, у которой и справа, и снизу стена (или край поля). Поэтому нужно перебрать все такие клетки и взять наибольшую и наименьшую из накопленных в них сумм.
В приложенном файле поле имеет размер 20×20. Вертикальные стены (нельзя идти вправо) стоят:
- между 4-м и 5-м столбцами — в строках 12–16;
- между 7-м и 8-м столбцами — в строках 4–19;
- между 12-м и 13-м столбцами — в строках 2–11;
- между 17-м и 18-м столбцами — в строках 11–18;
- между 19-м и 20-м столбцами — в строках 5–10.
Горизонтальные стены (нельзя идти вниз) стоят между 4-й и 5-й строками в столбцах 16–19, между 11-й и 12-й строками в столбцах 10–12, между 16-й и 17-й строками в столбцах 2–4, между 18-й и 19-й строками в столбцах 13–17 и между 19-й и 20-й строками в столбцах 5–7.
Скопируем содержимое таблицы в текстовый файл 18.txt (числа разделены пробелами или знаками табуляции) и обработаем его программой.
f = open('18.txt')
a = [[int(x) for x in s.split()] for s in f]
N = len(a)
# стена снизу от клетки (i, j); строки и столбцы нумеруются с нуля
def wall_down(i, j):
return ((i == 3 and 15 <= j <= 18) or (i == 10 and 9 <= j <= 11) or
(i == 15 and 1 <= j <= 3) or (i == 17 and 12 <= j <= 16) or
(i == 18 and 4 <= j <= 6))
# стена справа от клетки (i, j)
def wall_right(i, j):
return ((j == 11 and 1 <= i <= 10) or (j == 6 and 3 <= i <= 18) or
(j == 18 and 4 <= i <= 9) or (j == 16 and 10 <= i <= 17) or
(j == 3 and 11 <= i <= 15))
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]
best_max = 0
best_min = 10 ** 9
for i in range(N):
for j in range(N):
# клетка конечная, если справа и снизу от неё стена (или край поля)
if (j == N - 1 or wall_right(i, j)) and (i == N - 1 or wall_down(i, j)):
best_max = max(best_max, MX[i][j])
best_min = min(best_min, MN[i][j])
print(best_max, best_min)
Конечных клеток оказывается пять; накопленные в них суммы такие:
| Конечная клетка (строка, столбец) | Максимум | Минимум |
| (11, 12) | 1431 | 870 |
| (16, 4) | 1173 | 820 |
| (18, 17) | 2252 | 1369 |
| (19, 7) | 1566 | 947 |
| (20, 20) | 2255 | 1577 |
Наибольшая из всех итоговых сумм — 2255 (правая нижняя клетка), наименьшая — 820 (клетка в 16-й строке и 4-м столбце).
Ответ: 2255 820