Розв’язування грубої сили нонограмою


25

Фон

Нонограма , також відома як Picross або Griddlers, - це головоломка, де мета - визначити, чи повинна кожна клітинка в 2D сітці бути кольоровою або залишена порожньою, використовуючи кількість послідовних кольорових комірок у кожному рядку.

Далі наводиться приклад головоломки з розв'язкою.

Проблема полягає в тому, що деякі комерційні ігри з програмою 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?
Leaky Nun

Коли ви гадаєте, чи мусите ви здогадуватися, що клітина чорна, чи ви можете здогадуватися або чорною, або білою?
feersum

@LeakyNun Це недійсний рядок. Ви можете припустити, що введення завжди є дійсним рядком Nonogram.
Бубон

@feersum Ви завжди здогадуєтесь про кольорові клітини. У реальних іграх здогадка про порожню клітинку (правильну чи неправильну) не впливає на ваше життя, тому ви не можете отримати зворотного зв’язку з нею.
Бубон

Фантастичний виклик
Енріко Борба

Відповіді:


19

Рубін , 85 байт

f=->l,n,s=n-l.sum-l.size+1{*a,b=l;b&&s>0?(a[0]?1+f[a,n-b-2,s-1]:(n.to_f/b).ceil-1):0}

Спробуйте в Інтернеті!

Пояснення

l=[l1,l2,...,lx]xn

lx
nlx
nlx1+f(l,nlx)
1+f(l~,nlx2)l~l

f(l,n)={0,if 1xli+x1nnlx1if x=11+max{f(l,nlx)f(l~,nlx2),otherwise

Ось приклад _невідомо, Xце відомий простір, Oвідома кольорова клітина і Lжиття втрачено

[2,2,4] 15                  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
(1) -> [2,2,4] 11           _ _ _ _ _ _ _ _ _ _ _ L X X X
    (1) -> [2,2,4] 7        _ _ _ _ _ _ _ L X X X L X X X
        0                   X X X L X X X L X X X L X X X
    (2) -> [2,2] 5          _ _ _ _ _ X O O O O L L X X X
        0                   O O X O O X O O O O L L X X X 
(2) -> [2,2] 9              _ _ _ _ _ _ _ _ _ X O O O O L
    (1) -> [2,2] 7          _ _ _ _ _ _ _ L X X O O O O L
        (1) -> [2,2] 5      _ _ _ _ _ L X L X X O O O O L
            0               O O X O O L X L X X O O O O L
        (2) -> [2] 3        _ _ _ X O O L L X X O O O O L
            1               O O L X O O L L X X O O O O L               
    (2) -> [2] 5            _ _ _ _ _ X O O L X O O O O L
        2                   O O L L X X O O L X O O O O L

O(2n)

h

h(l,n)=n1xlix+1

h

h

h(l,nlx)=nlx1xlix+1=(n1xlix+1)lx=h(l,n)lx

h(l~,nlx2)=nlx21x1li(x1)+1=(n1xlix+1)1=h(l,n)1

h(l,n)={0,if 1xli+x1nnlx,if x=1max{h(l,nlx)+lxh(l~,nlx2)+1,otherwise

h

[h(l,nlx)+lx][h(l~,nlx2)+1]=nlxn1xlix+1+lx[nlx21x1li(x1)+1+1]=2

[h(l,nlx)+lx][h(l~,nlx2)+1]=2[h(l,nlx)+lx][h(l~,nlx2)+1]<0[h(l,nlx)+lx]<[h(l~,nlx2)+1]

h(l,n)={0,if 1xli+x1nnlx,if x=1h(l~,nlx2)+1otherwise

hfh

f(l,n)={0,if 1xli+x1nnlx1if x=11+f(l~,nlx2),otherwise

nO(n)


2
Ласкаво просимо в PPCG, неймовірний перший пост!
коул

1
@cole Це не перший їхній пост, але це, безумовно, неймовірно! Дуже розумний підхід +1
Містер Xcoder

1
Дивовижна робота. Я вручу нагороду через 2 дні, якщо до цього часу ніхто не знайде серйозного логічного недоліку.
Бубон

2

Python, 303 289 байт

Спочатку гольф тривалий час, тому може бути багато зайвого жиру. (Дякую Джо Кінгу, що знайшов 14 байт.)

Функція f створює всі можливі домовленості (хоча завжди з порожнім, як перший символ, але це добре, якщо ми збільшимо довжину на 1, перш ніж називати це). Функція g вибирає положення з найменшою кількістю заготовок і повторюється. Функція h з'єднує їх.

f=lambda l,n:["."*i+"X"*l[0]+c for i in range(1,n-l[0]+1)for c in f(l[1:],n-i-l[0])]if l else["."*n]
def g(q,n):O,X=min([[[p[:i]+p[i+1:]for p in q if p[i]==u]for u in".X"]for i in range(n)],key=lambda x:len(x[0]));return(len(q)>1)*1and max(1+g(O,n-1),g(X,n-1))
h=lambda l,n:g(f(l,n+1),n+1)

Усі приклади працюють добре:

>>> h([3,7],15)
2
>>> h([3,4],15)
3
>>> h([1,1,1,2,1],15)
6


1
Ви дозволили повернутися 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)і він буде по- , як і раніше зберегти один байт
Захарі

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)
Zacharý

2
Крім того, вам не потрібно рахувати кількість h=байтів
Zacharý

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.