Представьте сетку квадратов W на H, которая оборачивается тороидально. Элементы размещаются на сетке следующим образом.
Первый элемент можно разместить на любом квадрате, но последующие элементы не должны находиться в пределах манхэттенского расстояния R от любого предыдущего элемента (также известного как окрестность фон Неймана диапазона R ). Тщательный выбор позиций позволяет разместить большое количество элементов в сетке, прежде чем больше не будет действительных позиций. Однако вместо этого рассмотрите противоположную цель: Какое наименьшее количество предметов может быть размещено и не оставит больше действительных позиций?
Вот зона отчуждения радиуса 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
Фрагмент, чтобы помочь визуализировать и поиграть с идеями
canvas = document.getElementById('gridCanvas');ctx = canvas.getContext('2d');widthSelector = document.getElementById('width');heightSelector = document.getElementById('height');radiusSelector = document.getElementById('radius');itemCount = document.getElementById('itemCount');canvasMaxWidth = canvas.width;canvasMaxHeight = canvas.height;gridlineColour = '#888';emptyColour = '#ddd';itemColour = '#420';hoverCellColour = '#840';exclusionColour = '#d22';validColour = '#8f7';invalidColour = '#fbb';overlapColour = '#600';resetGrid();x = -1;y = -1;function resetGrid() {gridWidth = widthSelector.value;gridHeight = heightSelector.value;radius = radiusSelector.value;numberOfItems = 0;itemCount.value = numberOfItems + ' items placed.';cells = [gridWidth * gridHeight];for (i=0; i<gridWidth*gridHeight; i++) {cells[i] = '#ddd';}cellSize = Math.min(Math.floor(canvasMaxWidth/gridWidth), Math.floor(canvasMaxHeight/gridHeight));pixelWidth = gridWidth * cellSize + 1;canvas.width = pixelWidth;pixelHeight = gridHeight * cellSize + 1;canvas.height = pixelHeight;leaveCanvas();}function checkPosition(event) {bound = canvas.getBoundingClientRect();canvasX = event.clientX - bound.left;canvasY = event.clientY - bound.top;newX = Math.min(Math.floor(canvasX / cellSize), gridWidth-1);newY = Math.min(Math.floor(canvasY / cellSize), gridHeight-1);if (newX != x || newY != y) {x = newX;y = newY;drawGrid();}}function leaveCanvas() {x = -1;y = -1;drawGrid();}function drawGrid() {ctx.fillStyle = gridlineColour;ctx.fillRect(0, 0, pixelWidth, pixelHeight);cellColour = cells[x + gridWidth * y];if (cellColour == itemColour || cellColour == exclusionColour) {zoneColour = invalidColour;} else {zoneColour = validColour;}for (gridX=0; gridX<gridWidth; gridX++) {for (gridY=0; gridY<gridHeight; gridY++) {colour = (cells[gridX + gridWidth * gridY]);if (x >= 0 && y >= 0) {if (x == gridX && y == gridY) {colour = hoverCellColour;} else if (manhattanDistance(x, y, gridX, gridY) <= radius) {if (colour == exclusionColour) {colour = overlapColour;} else if (colour != itemColour) {colour = zoneColour;}}}ctx.fillStyle = colour;ctx.fillRect(gridX * cellSize + 1, gridY * cellSize + 1, cellSize - 1, cellSize - 1);}}}function manhattanDistance(a, b, c, d) {horizontal = Math.min(Math.abs((gridWidth + c - a) % gridWidth), Math.abs((gridWidth + a - c) % gridWidth));vertical = Math.min(Math.abs((gridHeight + d - b) % gridHeight), Math.abs((gridHeight + b - d) % gridHeight));return vertical + horizontal;}function placeItem(event) {bound = canvas.getBoundingClientRect();canvasX = event.clientX - bound.left;canvasY = event.clientY - bound.top;attemptX = Math.min(Math.floor(canvasX / cellSize), gridWidth-1);attemptY = Math.min(Math.floor(canvasY / cellSize), gridHeight-1);colour = cells[attemptX + gridWidth * attemptY];if (colour != itemColour && colour != exclusionColour) {for (a=0; a<gridWidth; a++) {for (b=0; b<gridHeight; b++) {if (manhattanDistance(a, b, attemptX, attemptY) <= radius) {cells[a + gridWidth * b] = exclusionColour;}}}cells[attemptX + gridWidth * attemptY] = itemColour;drawGrid();numberOfItems++;itemCount.value = numberOfItems + ' items placed.';}}
<canvas id='gridCanvas' width='500' height='300' style='border:none' onmousemove='checkPosition(event)' onmouseleave='leaveCanvas()' onclick='placeItem(event)'></canvas><br><textarea id='itemCount' readonly></textarea><br><button id='reset' onclick='resetGrid()'>Reset</button> with the following values:<br>Width:<input id='width' type='number' value='20' min='1' max='50' maxlength='2' step='1'><br>Height:<input id='height' type='number' value='13' min='1' max='30' maxlength='2' step='1'><br>Radius:<input id='radius' type='number' value='5' min='0' max='60' maxlength='2' step='1'>
Пример (безгольфовое) решение
Просто пример для небольших выходных данных (в результате радиус не намного меньше, чем ширина и высота). Может обрабатывать любой из тестовых случаев, но будет превышать время ожидания и сдаваться для большинства более крупных случаев.
itemCount = document.getElementById('itemCount')
calculateButton = document.getElementById('calculate')
widthSelector = document.getElementById('width')
heightSelector = document.getElementById('height')
radiusSelector = document.getElementById('radius')
function calculate() {
calculateButton.disabled = true
widthSelector.disabled = true
heightSelector.disabled = true
radiusSelector.disabled = true
itemCount.value = 'Calculating...'
setTimeout(delayedCalculate, 100)
}
function delayedCalculate() {
gridWidth = widthSelector.value
gridHeight = heightSelector.value
radius = radiusSelector.value
startingMin = gridWidth*gridHeight + 1
var cells = [gridWidth * gridHeight]
for (i=0; i<gridWidth*gridHeight; i++) {
cells[i] = 0
}
var gridState = gridWithItemAdded(cells, 0, 0)
var minimum = minFromHere(gridState) + 1
itemCount.value = 'Minimum ' + minimum + ' items required.'
calculateButton.disabled = false
widthSelector.disabled = false
heightSelector.disabled = false
radiusSelector.disabled = false
}
function minFromHere(gridState) {
var x
var y
var newGridState
var noCells = true
var min = startingMin
for (x=0; x<gridWidth; x++) {
for (y=0; y<gridHeight; y++) {
if (gridState[x + gridWidth * y] == 0) {
noCells = false
newGridState = gridWithItemAdded(gridState, x, y)
m = minFromHere(newGridState)
if (m < min) {
min = m
}
}
}
}
if (noCells) return 0
return min + 1
}
function gridWithItemAdded(gridState, x, y) {
var a
var b
var grid = gridState.slice()
for (a=0; a<gridWidth; a++) {
for (b=0; b<gridHeight; b++) {
if (manhattanDistance(a, b, x, y) <= radius) {
grid[a + gridWidth * b] = 1
}
}
}
return grid
}
function manhattanDistance(a, b, c, d) {
horizontal = Math.min(Math.abs((gridWidth + c - a) % gridWidth), Math.abs((gridWidth + a - c) % gridWidth))
vertical = Math.min(Math.abs((gridHeight + d - b) % gridHeight), Math.abs((gridHeight + b - d) % gridHeight))
return vertical + horizontal
}
<textarea id='itemCount' readonly></textarea>
<br>
<button id='calculate' onclick='calculate()'>Calculate</button> with the following values:
<br>
Width:<input id='width' type='number' value='5' min='1' max='50' maxlength='2' step='1'>
<br>
Height:<input id='height' type='number' value='4' min='1' max='30' maxlength='2' step='1'>
<br>
Radius:<input id='radius' type='number' value='1' min='0' max='60' maxlength='2' step='1'>
Ответы:
Python 2,
216182 байтаВвод как
f(16,16,8)
. Использует тот же алгоритм, что и в примере @ trichoplax , но с множествами. Первоначально я не помещал первый элемент в(0, 0)
, но это сделало его удушающим в последних нескольких случаях.Все вышеуказанные дела завершаются в течение 10 секунд, что значительно ниже предела. На самом деле, случаи настолько малы, что у меня было немного места, чтобы быть менее эффективным, что позволило мне убрать проверку, которая проверяла наличие дублированных состояний.
(Спасибо @trichoplax за помощь в игре в гольф)
Expanded:
источник
Питон 3,
270262260251246226(Спасибо Sp3000 за:
-~
вместо того+1
, что позволяет мне потерять пробел послеreturn
последней строки.W*H
.%
дает положительный результат для отрицательных чисел, чтобы сохранить еще 20 байтов)Это пример ответа JavaScript из вопроса, перенесенного в Python 3.
Чтобы избежать необходимости передавать столько аргументов функции, я переместил две вспомогательные функции в функцию вычисления, чтобы они разделяли ее область действия. Я также сжал каждую из этих функций в одну строку, чтобы избежать затрат на отступы.
объяснение
Этот подход довольно грубой силы помещает первый элемент в (0, 0), а затем отмечает все исключенные квадраты. Затем он рекурсивно размещает элемент на всех оставшихся действительных квадратах, пока все квадраты не будут исключены, и возвращает минимальное количество требуемых элементов.
Гольф-код:
Ungolfed код:
Код ungolfed определяет функцию, а также содержит код, позволяющий вызывать ее из командной строки. Код для игры в гольф просто определяет функцию, которая достаточна для стандартных вопросов по гольфу .
Если вы хотите протестировать гольф-код из командной строки, то здесь с включенной обработкой командной строки (но не для игры в гольф):
Командная строка проверяемый гольф-код
источник