Найгірше виключення Манхеттена


20

Уявіть сіткою W від H квадратів, які обгортаються тороїдно. Елементи розміщуються на сітці наступним чином.

Перший елемент може бути розміщений на будь-якому квадраті, але наступні елементи не повинні знаходитися в межах Манхеттенської відстані R від будь-якого попереднього елемента (також відомого як околиці Фон-Неймана діапазону R ). Ретельний вибір позицій дозволяє помістити велику кількість предметів на сітку до того, як немає більше дійсних позицій. Однак замість цього врахуйте протилежну мету: яка найменша кількість предметів, які можна розмістити, і не залишати більше дійсних позицій?

Ось радіус 5 зони відчуження:

Радіус 5 зони відчуження

Ось ще одна зона відчуження радіусом 5, на цей раз біля країв, тому поведінка загортання очевидна:

Радіус обгортання 5 зони відчуження

Вхідні дані

Три цілих числа:

  • W : ширина сітки (натуральне число)
  • H : висота сітки (натуральне число)
  • R : радіус зони відчуження (невід'ємне ціле число)

Вихідні дані

Ціле число N - це найменша кількість елементів, які можна розмістити, запобігаючи подальшим дійсним розміщенням.

Деталі

  • Радіус нуля дає зону виключення в 1 квадрат (ту, на яку був розміщений предмет).
  • Радіус N виключає зону, до якої можна дійти N ортогональних кроків (пам'ятайте, що краї обертаються тороїдально).

Ваш код повинен працювати для тривіального випадку R = 0, але не потрібно працювати для W = 0 або H = 0.

Ваш код повинен також мати справу з випадком , коли R > W або R > H .

Ліміт часу та тестові випадки

Ваш код повинен мати можливість вирішувати всі тестові справи, і кожен тестовий випадок повинен завершитися протягом 5 хвилин. Це повинно бути простим (приклад рішення JavaScript займає кілька секунд для кожного тестового випадку). Час обмеження полягає в основному, щоб виключити екстремальний підхід. Приклад підходу все ще є досить грубою силою.

Якщо ваш код заповниться протягом 5 хвилин на одній машині, а не на іншій, це буде досить близько.

Тестові приклади у формі входів: вивести якW H R : N

5 4 4 : 1
5 4 3 : 2
5 4 2 : 2
5 4 1 : 5

7 5 5 : 1
7 5 4 : 2
7 5 3 : 2
7 5 2 : 4

8 8 8 : 1
8 8 7 : 2
8 8 6 : 2
8 8 5 : 2
8 8 4 : 2
8 8 3 : 4

 7  6  4 : 2
 7  6  2 : 4
11  7  4 : 3
11  9  4 : 4
13 13  6 : 3
11 11  5 : 3
15 14  7 : 2
16 16  8 : 2

Фрагмент, щоб допомогти візуалізувати та пограти з ідеями

Приклад (необолочений) розчин

Просто приклад для невеликих виходів (в результаті радіус не набагато менший за ширину та висоту). Може працювати з будь-яким із тестових випадків, але час вичерпається та відмовиться від більшості великих випадків.


4
Дивовижний фрагмент коду!
Стретч-маніяк

@StretchManiac спасибі :) Я намагаюся вивчити JavaScript, тому будь-який відгук вітається
trichoplax

1
Це досить приємний фрагмент. Мені також подобається ця колірна гамма. Це з палітри?
милі

@miles спасибі - кольори просто здогадуються, а потім трохи налаштовуються (але не дуже багато - вони все ще є 3 кольоровими кодами кольорів, а не 6). Ви можете бачити кольори, які використовуються в третьому блоці рядків у фрагменті коду.
трихоплакс

Відповіді:


5

Python 2, 216 182 байт

def f(W,H,R):L={(i%W,i/W)for i in range(W*H)};M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R};g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1]);return g(M)

Вхід як f(16,16,8). Використовує такий же алгоритм, як і зразок @ trichoplax , але з наборами. Спочатку я не розміщував перший предмет (0, 0), але це змусило задихнутися в останніх кількох випадках.

Усі вищезазначені справи закінчуються протягом 10 секунд, що знаходиться під обмеженням. Насправді випадки досить малі, що у мене було мало місця, щоб бути менш ефективним, що дозволило мені зняти чек, який перевіряв на наявність дублікатів станів.

(Дякуємо @trichoplax за допомогу в гольфі)

Розширено:

def f(W,H,R):
  # All cells
  L={(i%W,i/W)for i in range(W*H)}                 

  # Mask: Complement of exclusion zone around (0, 0) 
  M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R}

  # Place recursively
  g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1])
  return g(M)

2

Пітон 3, 270 262 260 251 246 226

(Завдяки Sp3000 за:

  • -~ замість цього +1 , що дозволяє мені втратити пробіл після return останнього рядка.
  • втрачаючи зайві дужки навколо W*H .
  • лямбда ...
  • ставлячи все в одну лінію.
  • модуль python %дає позитивний результат для негативних чисел, щоб зберегти ще 20 байт)

Це відповідь на приклад JavaScript у запитанні, яке було подано на Python 3.

Щоб уникнути необхідності передавати стільки аргументів функції, я перемістив дві підтримуючі функції всередині функції обчислення, щоб вони поділили її сферу застосування. Я також конденсував кожну з цих функцій в один рядок, щоб уникнути витрат на відступ.

Пояснення

Цей досить жорстокий підхід ставить перший елемент у (0, 0), а потім позначає всі виключені квадрати. Потім рекурсивно розміщує елемент на всіх реальних квадратиках, поки всі квадрати не виключені, і повертає необхідну мінімальну кількість елементів.

Код для гольфу:

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

Невикористаний код:

def calculate(W, H, R):
    starting_min = W * H + 1
    cells = [0] * (W * H)
    grid_state = grid_with_item_added(cells, 0, 0, W, H, R)
    return min_from_here(grid_state, starting_min, W, H, R) + 1

def min_from_here(grid_state, starting_min, W, H, R):
    no_cells = True
    min = starting_min
    for x in range(W):
        for y in range(H):
            if grid_state[x + W * y] == 0:
                no_cells = False
                new_grid_state = grid_with_item_added(grid_state, x, y, W, H, R)
                m = min_from_here(new_grid_state, starting_min, W, H, R)
                if m < min:
                    min = m

    if no_cells:
        return 0
    else:
        return min + 1

def grid_with_item_added(grid_state, x, y, W, H, R):
    grid = grid_state[:]
    for a in range(W):
        for b in range(H):
            if manhattan_distance(a, b, x, y, W, H) <= R:
                grid[a + W * b] = 1

    return grid

def manhattan_distance(a, b, c, d, W, H):
    horizontal = min(abs(W + c - a) % W, abs(W + a - c) % W)
    vertical = min(abs(H + d - b) % H, abs(H + b - d) % H)
    return horizontal + vertical


if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(calculate(int(arguments[0]), int(arguments[1]), int(arguments[2])))

Невикольований код визначає функцію, а також включає код, щоб дозволити її викликати з командного рядка. Код для гольфу просто визначає функцію, якої достатньо для стандартних питань гольфу з кодом .

Якщо ви хочете перевірити код golfed з командного рядка, ось він включає в себе обробку командного рядка (але не гольф):

Код командного рядка, який можна перевірити для гольфу

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(C(int(arguments[0]), int(arguments[1]), int(arguments[2])))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.