Stellen Sie sich ein W x H- Gitter von Quadraten vor, das sich toroidal umschließt. Die Elemente werden wie folgt in das Raster eingefügt.
Der erste Gegenstand kann auf ein beliebiges Feld gelegt werden, nachfolgende Gegenstände dürfen sich jedoch nicht innerhalb eines Manhattan-Abstands R zu einem vorherigen Gegenstand befinden (auch als Von Neumann-Nachbarschaft der Reichweite R bekannt ). Wenn Sie die Positionen sorgfältig auswählen, können Sie eine große Anzahl von Elementen in das Raster einfügen, bevor keine gültigen Positionen mehr vorhanden sind. Betrachten Sie stattdessen das gegenteilige Ziel: Was ist die niedrigste Anzahl von Elementen, die platziert werden können und keine weiteren gültigen Positionen belassen?
Hier ist eine Ausschlusszone mit Radius 5:
Hier ist eine weitere Ausschlusszone für Radius 5, diesmal in der Nähe der Kanten, damit das Umwicklungsverhalten ersichtlich wird:
Eingang
Drei ganze Zahlen:
- W : Breite des Gitters (positive ganze Zahl)
- H : Höhe des Gitters (positive ganze Zahl)
- R : Radius der Ausschlusszone (nicht negative ganze Zahl)
Ausgabe
Eine Ganzzahl N , die die kleinste Anzahl von Elementen darstellt, die platziert werden können, um weitere gültige Platzierungen zu verhindern.
Einzelheiten
- Ein Radius von Null ergibt eine Ausschlusszone von 1 Quadrat (dasjenige, auf das der Gegenstand gelegt wurde).
- Ein Radius von N schließt die Zone aus, die in N orthogonalen Schritten erreicht werden kann (denken Sie daran, dass die Kanten toroidal gewickelt sind).
Ihr Code muss für den einfachen Fall von R = 0 funktionieren, muss jedoch nicht für W = 0 oder H = 0 funktionieren .
Ihr Code muss sich auch mit dem Fall befassen, in dem R > W oder R > H ist .
Zeitlimit und Testfälle
Ihr Code muss in der Lage sein, alle Testfälle zu verarbeiten, und jeder Testfall muss innerhalb von 5 Minuten abgeschlossen sein. Dies sollte einfach sein (die Beispiel-JavaScript-Lösung dauert für jeden Testfall einige Sekunden). Das Zeitlimit besteht hauptsächlich darin, den extremen Brute-Force-Ansatz auszuschließen. Der beispielhafte Ansatz ist immer noch ziemlich brachial.
Wenn Ihr Code auf einem Computer innerhalb von 5 Minuten ausgeführt wird, auf einem anderen jedoch nicht, ist dies ausreichend.
Testfälle in den Formulareingaben: Ausgabe alsW 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 zum Visualisieren und Herumspielen von Ideen
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'>
Beispiel (ungolfed) Lösung
Nur ein Beispiel für kleine Leistungen (resultierend aus einem Radius, der nicht viel kleiner als die Breite und Höhe ist). Kann mit jedem der Testfälle umgehen, gibt aber bei den meisten größeren Fällen auf.
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'>
Antworten:
Python 2,
216182 BytesEingabe wie
f(16,16,8)
. Verwendet fast den gleichen Algorithmus wie @ trichoplax , jedoch mit Mengen. Ursprünglich habe ich den ersten Artikel nicht bei platziert(0, 0)
, aber dies hat ihn in den letzten Fällen zum Ersticken gebracht.Alle oben genannten Fälle sind innerhalb von 10 Sekunden abgeschlossen. Tatsächlich sind die Fälle so klein, dass ich etwas weniger effizient arbeiten konnte, sodass ich einen Scheck entfernen konnte, der nach doppelten Zuständen suchte.
(Danke an @trichoplax für die Hilfe beim Golfen)
Erweitert:
quelle
Python 3,
270262260251246226(Dank an Sp3000 für:
-~
stattdessen+1
, wodurch ich in der letzten Zeile ein Leerzeichen nachher verlierereturn
.W*H
.%
liefert positive Ergebnisse für negative Zahlen, um weitere 20 Bytes zu sparen)Dies ist die JavaScript-Beispielantwort von der in Python 3 portierten Frage.
Um zu vermeiden, dass so viele Funktionsargumente übergeben werden müssen, habe ich die beiden unterstützenden Funktionen in der Berechnungsfunktion so verschoben, dass sie den Gültigkeitsbereich teilen. Ich habe auch jede dieser Funktionen in einer einzigen Zeile zusammengefasst, um die Kosten für das Einrücken zu vermeiden.
Erläuterung
Bei diesem ziemlich brachialen Ansatz wird das erste Objekt auf (0, 0) gesetzt und anschließend alle ausgeschlossenen Felder markiert. Anschließend wird ein Element rekursiv an allen verbleibenden gültigen Feldern platziert, bis alle Felder ausgeschlossen sind, und die erforderliche Mindestanzahl von Elementen wird zurückgegeben.
Golf Code:
Ungolfed-Code:
Der ungolfed Code definiert eine Funktion und enthält auch Code, mit dem er über die Befehlszeile aufgerufen werden kann. Der Golf-Code definiert lediglich die Funktion, die für Standard-Code-Golf-Fragen ausreicht .
Wenn Sie den Golf Code von der Kommandozeile aus testen möchten, ist hier die Kommandozeilenbehandlung enthalten (aber nicht Golf):
Kommandozeilen testbarer Golf Code
quelle