Задний план
Nonogram , также известный как Picross или Griddlers, представляет собой головоломку, цель которой состоит в том, чтобы определить, должна ли каждая ячейка на двумерной сетке быть цветной или оставлена пустой, используя количество последовательных цветных ячеек в каждой строке.
Ниже приведен пример головоломки Nonogram с решением.
Проблема в том, что некоторые коммерческие игры / мобильные приложения Nonogram имеют загадки, которые не могут быть решены вручную (например, имеют несколько решений или требуют глубокого возврата). Тем не менее, они также предлагают несколько жизней игроку, где одна жизнь теряется, когда вы пытаетесь закрасить ячейку, правильный ответ которой пуст . Так что теперь пришло время перебрать эти неприятные «загадки»!
Чтобы упростить задачу, представьте только одну строку с ее подсказкой и ничего больше:
3 7 | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[3,7]
Являются ключами, а длина линии 15 сот. Поскольку у него есть несколько возможных решений, нам нужно рискнуть несколькими жизнями, чтобы полностью решить эту линию (т.е. определить все цветные ячейки).
Вызов
Учитывая строку с подсказками (список положительных целых чисел) и длину линии, найдите максимальное количество жизней, которые вы потеряете, предполагая, что вы перебираете линию с оптимальной стратегией.
Обратите внимание, что вы всегда угадываете цветные клетки . В реальных играх угадывание пустых ячеек (правильных или неправильных) не влияет на вашу жизнь, поэтому вы не можете «решить» головоломку таким образом.
Кроме того, вы можете предположить, что входные данные всегда представляют допустимую строку Nonogram, поэтому вам не нужно беспокоиться о чем-то подобном [6], 5
.
объяснение
Давайте сначала посмотрим на несколько простых примеров.
[1,2], 5
Для этой строки есть ровно три варианта ( O
цветная ячейка, .
пустая):
O . O O .
O . . O O
. O . O O
Если мы попробуем закрасить ячейку 0 (индекс на основе 0 слева), произойдет одно из следующего:
- Ячейка правильно окрашена. Теперь у нас есть две возможности, и мы можем выбирать между ячейкой 2 и ячейкой 4, чтобы полностью решить линию. В любом случае мы потеряем одну жизнь в худшем случае.
- Клетка пуста, и мы теряем жизнь. В этом случае мы уже определили уникальное решение для этой линии, поэтому мы закончили с 1 потерянной жизнью.
Следовательно, ответ для [1,2], 5
1.
[5], 10
Бинарный поиск? Нет.
Самый очевидный первый выбор - 4 или 5, который покажет одну возможность, если он пуст (по цене 1 жизни). Допустим, мы выбрали 4 в первую очередь. Если ячейка 4 действительно окрашена, мы расширяем ее влево, то есть пробуем 3, 2, 1 и 0 до тех пор, пока жизнь не будет потеряна (или ячейка 0 окрашена, и в итоге мы не тратим вообще никаких жизней). Всякий раз, когда жизнь теряется, мы можем однозначно определить решение, например, если мы увидим что-то вроде этого:
_ _ X O O _ _ _ _ _
тогда мы уже знаем ответ таков:
. . . O O O O O . .
Таким образом, ответ для [5], 10
также 1.
[3,7], 15
Начните с ячейки 11, которая, если она пуста, сразу покажет следующее решение.
O O O . O O O O O O O X . . .
Затем попробуйте 12, которое, если оно пустое, дает две возможности, которые могут быть решены ценой 1 дополнительной жизни.
O O O . . O O O O O O O X . .
. O O O . O O O O O O O X . .
Теперь попробуйте 2. Если пусто, это приводит к трем возможностям, которые могут быть решены аналогично [1,2], 5
примеру.
. . X O O O . O O O O O O O .
. . X O O O . . O O O O O O O
. . X . O O O . O O O O O O O
Если вы продолжите минимизировать риск таким способом, вы можете достичь любого решения с макс. 2 жизни потрачено.
Тестовые случаи
[1,2] 5 => 1
[2] 5 => 2
[1] 5 => 4
[] 5 => 0
[5] 10 => 1
[2,1,5] 10 => 0
[2,4] 10 => 2
[6] 15 => 2
[5] 15 => 2
[4] 15 => 3
[3,7] 15 => 2
[3,4] 15 => 3
[2,2,4] 15 => 4
[1,1,1,1,1,1,1] 15 => 2
[2,1,1,3,1] 15 => 3
[1,1,1,2,1] 15 => 5
Для последних двух случаев оптимальная стратегия - не проходить через минимальные пробелы, а просто проходить слева направо (или справа налево). Спасибо @crashoz за указание на это.
правила
Применяются стандартные правила игры в гольф . Побеждает самая короткая действительная передача в байтах.
премия
Если кто-то придумает алгоритм с полиномиальным временем (с доказательством правильности), я присуду +100 наград за такое решение.
источник
[6], 5
?Ответы:
Рубин , 85 байт
Попробуйте онлайн!
объяснение
Вот пример
_
неизвестны,X
это известное пространство,O
это известная цветная клетка иL
потеря жизниЭто делает бинарное дерево, чтобы получить количество потерянных жизней, нам просто нужно посчитать максимальную высоту дерева. Однако это делает его потому что мы оцениваем все ветви. Мы можем сделать лучше.O(2n)
Давайте определим функцию стоимости , которая поможет нам «выбрать» правильную ветвь на каждом шаге.h
По определению имеем:h
И,
Тогда
Мы хотим максимизировать на каждом шаге, чтобы получить худший случай, поэтому давайте проверим разницу между двумя выражениями в повторяемостиh
Наконец, это рекурсивное определение показывает нам, что опция (2) в функции всегда является наихудшим случаем (давая максимальное количество возможностей, т.е. максимизируя )h f h
Каждый шаг мы уменьшаем как минимум на 3, и теперь есть один рекурсивный вызов, сложностьO ( n )n O(n)
источник
Python,
303289 байтПервый гольф в течение длительного времени, поэтому может быть много лишнего жира. (Спасибо, Джо Кинг, что нашел 14 байтов.)
Функция f генерирует все возможные расположения (хотя всегда с пробелом в качестве первого символа, но это нормально, если мы увеличиваем длину на 1, прежде чем мы ее вызовем). Функция g выбирает позицию с наименьшим количеством пробелов и рекурсов. Функция h объединяет их.
Все примеры работают нормально:
источник
False
к0
? Если это так, вы можете изменить(len(q)>1)*1and
наlen(q)>1and
. Если вы не можете вернутьсяFalse
к0
, а затем сделать это, но изменениеg(f(l,n+1),n+1)
в ,1*g(f(l,n+1),n+1)
и он будет по- прежнему сохранить один байтFalse
нельзя0
вместо того,g(f(l,n+1),n+1)
чтобы1*g(f(l,n+1),n+1)
менять его на+g(f(l,n+1),n+1)
h=
байтов