Imagine uma grade de quadrados W por H que envolve toroidalmente. Os itens são colocados na grade da seguinte maneira.
O primeiro item pode ser colocado em qualquer quadrado, mas os itens subsequentes não devem estar a uma distância de Manhattan R de nenhum item anterior (também conhecido como bairro de Von Neumann, no intervalo R ). A escolha cuidadosa das posições permite ajustar um grande número de itens na grade antes que não haja mais posições válidas. No entanto, considere o objetivo oposto: qual é o menor número de itens que podem ser colocados e não deixam mais posições válidas?
Aqui está uma zona de exclusão do raio 5:
Aqui está outra zona de exclusão do raio 5, desta vez próxima às bordas, para que o comportamento de quebra seja aparente:
Entrada
Três inteiros:
- W : largura da grade (número inteiro positivo)
- H : altura da grade (número inteiro positivo)
- R : raio da zona de exclusão (número inteiro não negativo)
Saída
Um número inteiro N , que é o menor número de itens que podem ser colocados, impedindo outros canais válidos.
Detalhes
- Um raio de zero fornece uma zona de exclusão de 1 quadrado (aquele em que o item foi colocado).
- Um raio de N exclui a zona que pode ser alcançada em N etapas ortogonais (lembre-se de que as arestas estão dispostas toroidalmente).
Seu código deve funcionar para o caso trivial de R = 0, mas não precisa funcionar para W = 0 ou H = 0.
Seu código também deve lidar com o caso em que R > W ou R > H .
Prazo e casos de teste
Seu código deve poder lidar com todos os casos de teste e cada caso de teste deve ser concluído em 5 minutos. Isso deve ser fácil (a solução JavaScript de exemplo leva alguns segundos para cada caso de teste). O prazo é principalmente para excluir a abordagem de força bruta extrema. A abordagem de exemplo ainda é uma força bastante bruta.
Se o seu código for concluído dentro de 5 minutos em uma máquina, mas não em outra, ela estará próxima o suficiente.
Casos de teste nas entradas do formulário: output asW 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 para ajudar a visualizar e brincar com idéias
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'>
Solução de exemplo (não destruída)
Apenas um exemplo para pequenas saídas (resultantes de um raio não muito menor que a largura e a altura). É capaz de lidar com qualquer um dos casos de teste, mas o tempo limite é interrompido e a maioria dos casos maiores.
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'>
Respostas:
Python 2,
216182 bytesEntrada como
f(16,16,8)
. Usa praticamente o mesmo algoritmo que da amostra do @ trichoplax , mas com conjuntos. Inicialmente, não coloquei o primeiro item(0, 0)
, mas isso o fez sufocar nos últimos casos.Todos os casos acima são concluídos em 10 segundos, bem abaixo do limite. De fato, os casos são pequenos o suficiente para que eu tivesse um pouco de espaço para ser menos eficiente, permitindo remover uma verificação que verificava estados duplicados.
(Obrigado a @trichoplax pela ajuda no golfe)
Expandido:
fonte
Python 3,
270262260251246226(Obrigado ao Sp3000 por:
-~
em vez de+1
, o que me permite perder um espaço depoisreturn
na última linha.W*H
.%
fornece resultado positivo para números negativos, para salvar outros 20 bytes)Este é o exemplo de resposta em JavaScript da pergunta portada no Python 3.
Para evitar ter que passar tantos argumentos de função, movi as duas funções de suporte dentro da função de cálculo para que elas compartilhem seu escopo. Também condensamos cada uma dessas funções em uma única linha para evitar o custo do recuo.
Explicação
Essa abordagem de força bastante bruta coloca o primeiro item em (0, 0) e marca todos os quadrados excluídos. Em seguida, coloca recursivamente um item em todos os quadrados válidos restantes até que todos os quadrados sejam excluídos e retorna o número mínimo de itens necessários.
Código de golfe:
Código não destruído:
O código não protegido define uma função e também inclui código para permitir que seja chamado a partir da linha de comando. O código golfed apenas define a função, que é suficiente para perguntas padrão do golf do código .
Se você deseja testar o código de golfe na linha de comando, aqui está o tratamento da linha de comando incluído (mas não no golfe):
Código testável da linha de comando
fonte