Um quebra-cabeça da parte superior da frente é um quebra-cabeça em que você é obrigado a construir uma forma tridimensional de blocos (geralmente cúbicos), com três vistas ortogonais: uma vista superior, uma vista frontal e uma vista lateral.
Por exemplo, com uma vista superior, frontal e lateral da seguinte maneira:
Top: Front: Side:
. . . . . . . . . . . .
. x x . . x x . . x x .
. x x . . x x . . x x .
. . . . . . . . . . . .
In this problem, the side view is taken from the right.
Um cubo 2x2x2 (com volume 8) satisfaria essa solução, mas é factível no volume 4, se tivermos a seguinte estrutura de camada:
. . . . . . . .
. x . . . . x .
. . x . . x . .
. . . . . . . .
Existem também alguns acordos insolúveis. Considere por exemplo:
Top: Front: Side:
. . . . . . . . . . . .
. . . . . . x . . . . .
. x . . . . . . . x . .
. . . . . . . . . . . .
Se a vista superior diz que o bloco é o segundo da esquerda, não há como corresponder à vista frontal que diz que o bloco deve ser o terceiro da esquerda. Portanto, esse arranjo é impossível.
Sua tarefa é criar um programa que, dado um quebra-cabeça arbitrário 4x4 na parte superior da frente, tente resolvê-lo no menor número de cubos ou o declare insolúvel.
Seu programa terá como entrada uma série de 48 bits, representando as vistas superior, frontal e lateral. Eles podem estar no formato que você desejar (uma sequência de 6 bytes, uma sequência de 0 e 1, um número hexadecimal de 12 dígitos etc.), mas a ordem dos bits deve ser mapeada da seguinte forma:
Top: 0x00 Front: 0x10 Side: 0x20
0 1 2 3 0 1 2 3 0 1 2 3
4 5 6 7 4 5 6 7 4 5 6 7
8 9 a b 8 9 a b 8 9 a b
c d e f c d e f c d e f
Em outras palavras, os bits vão na ordem da esquerda para a direita, de cima para baixo, na vista superior, depois frontal e lateral.
Seu programa produzirá uma série de 64 bits, indicando os cubos na grade 4x4x4 preenchidos ou indicará que a grade é insolúvel.
Seu programa será pontuado executando uma bateria de 1.000.000 de casos de teste.
Os dados de teste serão gerados usando os hashes MD5 dos números inteiros "000000" a "999999" como seqüências de caracteres, extraindo os primeiros 48 bits (12 hexágonos) de cada um desses hashes e usando-os como entrada para a parte superior frontal. quebra-cabeça lateral. Como exemplo, aqui estão algumas das entradas de teste e os quebra-cabeças que elas geram:
Puzzle seed: 000000 hash: 670b14728ad9
Top: Front: Side:
. x x . . . . x x . . .
x x x x . x . x x . x .
. . . . . x x x x x . x
x . x x . . x . x . . x
Puzzle seed: 000001 hash: 04fc711301f3
Top: Front: Side:
. . . . . x x x . . . .
. x . . . . . x . . . x
x x x x . . . x x x x x
x x . . . . x x . . x x
Puzzle seed: 000157 hash: fe88e8f9b499
Top: Front: Side:
x x x x x x x . x . x x
x x x . x . . . . x . .
x . . . x x x x x . . x
x . . . x . . x x . . x
Os dois primeiros são insolúveis, enquanto o último tem uma solução com as seguintes camadas, da frente para trás:
x . . . . . . . x x x . x x x .
. . . . x . . . . . . . . . . .
x . . . . . . . . . . . x x x x
x . . . . . . . . . . . x . . x
There are a total of 16 blocks here, but it can probably be done in less.
A pontuação do seu programa será determinada pelos seguintes critérios, em ordem decrescente de prioridade:
- O maior número de casos resolvidos.
- O menor número de blocos necessários para resolver esses casos.
- O código mais curto em bytes.
Você deve enviar e calcular a pontuação sozinho, o que exige que seu programa seja capaz de executar todos os 1.000.000 de casos de teste.
Respostas:
Python: 5360 casos de teste resolvidos usando 69519 blocos, 594 bytes
Esses devem ser os valores ideais.
Abordagem:
Primeiro, testarei se o caso de teste é realmente solucionável. Eu faço isso inicializando uma lista de comprimento 64 por unidades e defino todas as posições como zero, se o pixel correspondente das três visualizações for zero. Depois, visualizo o quebra-cabeça de todas as três direções e ver se as visualizações são iguais às visualizações de entrada. Se for igual, o quebra-cabeça é solucionável (já encontramos a pior solução), caso contrário, é insolúvel.
Depois, faço uma abordagem de ramificação e limite para encontrar a solução ideal.
Ramificação: Eu tenho uma função recursiva. A profundidade da recursão informa quantos valores já foram corrigidos. Em cada chamada da função, eu me chamo duas vezes, se o valor no índice atual for 1 (esse valor pode ser 0 ou 1 na solução ideal) ou uma vez, se o valor for 0 (deve ser zero na solução ideal).
Limite: Eu uso duas estratégias diferentes aqui.
Calculo as visualizações dos três lados em cada chamada de função e observo se elas ainda correspondem aos valores de entrada. Se eles não corresponderem, não chamo a função recursivamente.
Eu mantenho a melhor solução na memória. Já existem mais fixos no ramo atual do que na melhor solução, já posso fechar esse ramo. Além disso, posso estimar um limite inferior para o número de blocos ativados, que não são fixos. E a condição se torna
#number of activated fixed blocks + #lower bound of activated blocks (under the not fixed blocks) < #number of activated blocks in the best solution.
Aqui está o código Python. Ele define uma função
f
que espera 3 listas contendo 1s e 0s e retorna 0 (não solucionável) ou uma lista de 1s e 0s representando a solução ideal.O comprimento do código é 596 bytes / caracteres. E aqui está a estrutura de teste:
Você pode encontrar uma versão não destruída do programa aqui . Também é um pouco mais rápido.
Resultados:
5360 dos 1000000 quebra-cabeças são solucionáveis. No total, precisamos de 69519 blocos. O número de blocos varia de 6 a 18 blocos. O quebra-cabeça mais difícil levou cerca de 1 segundo para resolver. É o quebra-cabeça com a semente
"347177"
, que parecee tem uma solução ideal com 18 cubos. A seguir, são apresentados alguns de cima para cada uma das camadas:
O tempo total de execução para todos os casos de teste foi de aproximadamente 90 segundos. Eu usei o PyPy para executar o meu programa. CPython (o intérprete padrão do Python) é um pouco mais lento, mas também resolve todos os quebra-cabeças em apenas 7 minutos.
Você pode encontrar a saída completa aqui : A saída é auto-explicativa. Por exemplo, a saída do quebra-cabeça acima é:
fonte
5360 caixas resolvidas com 69519 blocos; 923 bytes
Isso também é ótimo. Ligue com uma matriz de uns e zeros. Lança a
NullPointerException
para entrada inválida. Alguma eficiência é sacrificada para o golfe. Ele ainda é concluído dentro de um tempo razoável para todas as 1000000 entradas de teste.Estratégia:
Na verdade, eu costumava jogar esse quebra-cabeça quando tinha 10 anos. Isso usa minha abordagem.
Passo 1:
Forme o cubo com mais blocos que se ajustem às visualizações fornecidas.
Passo 2:
Crie uma lista de peças removíveis. (Qualquer peça que tenha outra peça na linha está dentro, a coluna está dentro e a viga está dentro.)
Etapa 3:
Teste todas as formas possíveis para manter ou remover cada peça removível. (Via força bruta recursiva com poda.)
Passo 4:
Mantenha o melhor cubo válido.
Ungolfed:
Programa completo:
fonte