Wyobraź sobie siatkę kwadratów W na H, która owija się toroidalnie. Elementy są umieszczane na siatce w następujący sposób.
Pierwszy przedmiot można umieścić na dowolnym polu, ale kolejne przedmioty nie mogą znajdować się w odległości R Manhattanu od jakiegokolwiek poprzedniego przedmiotu (znanego również jako sąsiedztwo Von Neumanna w zakresie R ). Staranne wybranie pozycji pozwala na umieszczenie dużej liczby elementów na siatce, zanim nie będzie już żadnych prawidłowych pozycji. Zamiast tego rozważ przeciwny cel: jaka jest najniższa liczba przedmiotów, które można umieścić i nie pozostawiają żadnych dalszych ważnych pozycji?
Oto strefa wykluczenia w promieniu 5:
Oto kolejna strefa wykluczenia w promieniu 5, tym razem w pobliżu krawędzi, więc zachowanie zawijania jest widoczne:
Wejście
Trzy liczby całkowite:
- W : szerokość siatki (dodatnia liczba całkowita)
- H : wysokość siatki (dodatnia liczba całkowita)
- R : promień strefy wykluczenia (nieujemna liczba całkowita)
Wynik
Liczba całkowita N , która jest najmniejszą liczbą elementów, które można umieścić, uniemożliwiając dalsze prawidłowe umieszczenie.
Detale
- Promień zera daje strefę wykluczenia 1 kwadrat (ten, na którym został umieszczony przedmiot).
- Promień N wyklucza strefę, do której można dotrzeć w N stopni ortogonalnych (pamiętaj, że krawędzie zawijają się toroidalnie).
Twój kod musi działać w trywialnym przypadku R = 0, ale nie musi działać dla W = 0 lub H = 0.
Twój kod musi radzić sobie z przypadkiem, gdy R > W lub R > H .
Termin i przypadki testowe
Kod musi obsługiwać wszystkie przypadki testowe, a każdy przypadek testowy musi zostać ukończony w ciągu 5 minut. To powinno być łatwe (przykładowe rozwiązanie JavaScript zajmuje kilka sekund dla każdego przypadku testowego). Limit czasu ma głównie na celu wykluczenie podejścia o ekstremalnej brutalnej sile. Przykładowe podejście jest wciąż dość brutalne.
Jeśli kod zostanie ukończony w ciągu 5 minut na jednym komputerze, ale nie na innym, będzie wystarczająco blisko.
Przypadki testowe w postaci danych wejściowych: dane wyjściowe jakoW 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
Snippet, który pomaga wizualizować i bawić się pomysłami
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'>
Przykładowe rozwiązanie (niestosowane do golfa)
Tylko przykład dla małych wyjść (wynikających z promienia niewiele mniejszego niż szerokość i wysokość). Może obsłużyć dowolny z przypadków testowych, ale przekroczy limit czasu i zrezygnuje z większości większych przypadków.
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'>
Odpowiedzi:
Python 2,
216182 bajtówDane wejściowe jak
f(16,16,8)
. Korzysta z tego samego algorytmu co próbka @ trichoplax , ale z zestawami. Początkowo nie umieszczałem pierwszego przedmiotu(0, 0)
, ale sprawiło to, że zadławił się w kilku ostatnich przypadkach.Wszystkie powyższe sprawy zakończone w ciągu 10 sekund, znacznie poniżej limitu. W rzeczywistości przypadki są na tyle małe, że miałem trochę miejsca, aby być mniej wydajnym, co pozwoliło mi na usunięcie kontroli sprawdzającej, czy nie występują duplikaty stanów.
(Dzięki @trichoplax za pomoc w grze w golfa)
Rozszerzony:
źródło
Python 3,
270262260251246226(Podziękowania dla Sp3000 za:
-~
zamiast+1
, co pozwala mi stracić miejsce poreturn
ostatniej linii.W*H
.%
daje dodatni wynik dla liczb ujemnych, aby zapisać kolejne 20 bajtów)To jest przykładowa odpowiedź JavaScript na pytanie zadane w Pythonie 3.
Aby uniknąć konieczności przekazywania tak wielu argumentów funkcji, przesunąłem dwie funkcje pomocnicze do funkcji obliczeniowej, aby dzieliły jej zakres. Skondensowałem również każdą z tych funkcji w jednej linii, aby uniknąć kosztów wcięć.
Wyjaśnienie
To dość brutalne podejście ustawia pierwszy element na (0, 0), a następnie zaznacza wszystkie wykluczone kwadraty. Następnie rekurencyjnie umieszcza element na wszystkich pozostałych ważnych polach, aż wszystkie kwadraty zostaną wykluczone, i zwraca minimalną wymaganą liczbę elementów.
Kod do gry w golfa:
Nieskluczony kod:
Nieskluczony kod definiuje funkcję, a także zawiera kod umożliwiający jej wywołanie z wiersza poleceń. Kod do gry w golfa po prostu określa funkcję, która jest wystarczająca dla standardowych pytań golfowych .
Jeśli chcesz przetestować kod do gry w golfa z wiersza poleceń, oto on z obsługą wiersza poleceń (ale nie golfem):
Kod do gry w golfa do testowania z linii poleceń
źródło