fundo
Nonogram , também conhecido como Picross ou Griddlers, é um quebra-cabeça em que o objetivo é determinar se cada célula na grade 2D deve ser colorida ou deixada em branco, usando o número de células coloridas consecutivas em cada linha.
A seguir, é apresentado um exemplo de quebra-cabeça Nonogram com solução.
O problema é que alguns jogos / aplicativos móveis Nonogram comerciais têm quebra-cabeças que não podem ser solucionados manualmente (por exemplo, possuem várias soluções ou exigem um retorno profundo). No entanto, eles também oferecem algumas vidas ao jogador, onde uma vida é perdida quando você tenta colorir uma célula cuja resposta correta está em branco . Então agora é hora de forçar com força esses "quebra-cabeças" desagradáveis!
Para simplificar a tarefa, imagine apenas uma linha com sua pista e nada mais:
3 7 | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
O [3,7]
são as pistas, e o comprimento da linha é de 15 células. Como possui várias soluções possíveis, precisamos arriscar algumas vidas para resolver completamente essa linha (ou seja, determinar todas as células coloridas).
Desafio
Dada uma linha com pistas (uma lista de números inteiros positivos) e o comprimento da linha, encontre o número máximo de vidas que você perderá, assumindo que você força a linha com força, com uma estratégia ideal.
Observe que você sempre adivinha células coloridas . Em jogos reais, adivinhar células vazias (certas ou erradas) não afeta sua vida; portanto, você não pode "resolver" o quebra-cabeça dessa maneira.
Além disso, você pode assumir que a entrada sempre representa uma linha Nonogram válida, para que você não precise se preocupar com algo parecido [6], 5
.
Explicação
Vejamos alguns exemplos mais simples primeiro.
[1,2], 5
Existem exatamente três possibilidades para essa linha ( O
é uma célula colorida, .
é uma célula vazia):
O . O O .
O . . O O
. O . O O
Se tentarmos colorir a célula 0 (índice baseado em 0 da esquerda), acontece um dos seguintes:
- A célula está colorida corretamente. Agora, temos duas possibilidades e podemos escolher entre as células 2 e 4 para resolver completamente a linha. Em ambos os casos, perderemos uma vida no pior caso.
- A célula está vazia e perdemos uma vida. Nesse caso, já identificamos a solução exclusiva para essa linha, então terminamos com 1 vida perdida.
Portanto, a resposta para [1,2], 5
é 1.
[5], 10
Pesquisa binária? Não.
A primeira escolha mais óbvia é 4 ou 5, o que revelará uma possibilidade se estiver em branco (a um custo de 1 ponto de vida). Digamos que escolhemos 4 primeiro. Se a célula 4 for realmente colorida, nós a estenderemos para a esquerda, ou seja, tente 3, 2, 1 e 0 até que uma vida seja perdida (ou a célula 0 seja colorida, acabamos sem passar nenhuma vida). Sempre que uma vida é perdida, podemos determinar exclusivamente a solução, por exemplo, se virmos algo assim:
_ _ X O O _ _ _ _ _
já sabemos que a resposta é esta:
. . . O O O O O . .
Portanto, a resposta para [5], 10
também é 1.
[3,7], 15
Comece com a célula 11, que, se vazia, revelará a solução a seguir imediatamente.
O O O . O O O O O O O X . . .
Em seguida, tente 12, que, se vazio, oferece duas possibilidades que podem ser resolvidas ao custo de 1 vida útil extra.
O O O . . O O O O O O O X . .
. O O O . O O O O O O O X . .
Agora tente 2. Se vazio, ele leva a três possibilidades que podem ser resolvidas de maneira semelhante ao [1,2], 5
exemplo.
. . X O O O . O O O O O O O .
. . X O O O . . O O O O O O O
. . X . O O O . O O O O O O O
Se você continuar minimizando o risco dessa maneira, poderá encontrar qualquer solução com no máx. 2 vidas gastas.
Casos de teste
[1,2] 5 => 1
[2] 5 => 2
[1] 5 => 4
[] 5 => 0
[5] 10 => 1
[2,1,5] 10 => 0
[2,4] 10 => 2
[6] 15 => 2
[5] 15 => 2
[4] 15 => 3
[3,7] 15 => 2
[3,4] 15 => 3
[2,2,4] 15 => 4
[1,1,1,1,1,1,1] 15 => 2
[2,1,1,3,1] 15 => 3
[1,1,1,2,1] 15 => 5
Nos dois últimos casos, a estratégia ideal não é passar pelos espaços em branco mínimos, mas simplesmente ir da esquerda para a direita (ou da direita para a esquerda). Obrigado a @crashoz por apontar isso.
Regras
Aplicam-se as regras de código-golfe padrão . O menor envio válido em bytes vence.
Recompensa
Se alguém criar um algoritmo de tempo polinomial (com a prova de correção), concederei +100 de recompensa a essa solução.
fonte
[6], 5
?Respostas:
Ruby , 85 bytes
Experimente online!
Explicação
Aqui está um exemplo
_
são desconhecidos,X
é um espaço conhecido,O
é uma célula colorida conhecida eL
sua vida é perdidaFaz uma árvore binária, para obter o número de vidas perdidas, precisamos apenas contar a altura máxima da árvore. No entanto, isso o torna porque avaliamos todos os ramos. Nós podemos fazer melhor.O ( 2n)
Vamos definir uma função de custo que nos ajude a "escolher" o ramo certo em cada etapa.h
Por definição de , temos,h
E,
Então,
Queremos maximizar em cada etapa para obter o pior caso, então vamos verificar a diferença entre as duas expressões na recorrênciah
Finalmente, essa definição recursiva de mostra que a opção (2) na função é sempre o pior caso (fornecendo o número máximo de possibilidades, ou seja, maximizando )h f h
A cada passo, diminuímos em pelo menos 3 e agora há uma única chamada recursiva, a complexidade éO ( n )n O(n)
fonte
Python,
303289 bytesPrimeiro golfe há muito tempo, portanto pode haver muito excesso de gordura. (Obrigado Jo King por encontrar 14 bytes de valor.)
A função f gera todos os arranjos possíveis (embora sempre com um espaço em branco como o primeiro caractere, mas tudo bem, desde que incrementemos o comprimento em 1 antes de chamá-lo). A função g seleciona a posição com o menor número de espaços em branco e se repete. A função h os une.
Todos os exemplos funcionam bem:
fonte
False
para0
? Nesse caso, você pode mudar(len(q)>1)*1and
paralen(q)>1and
. Se você não tem permissão para voltarFalse
para0
, em seguida, fazer isso, mas a mudançag(f(l,n+1),n+1)
para1*g(f(l,n+1),n+1)
e vai ainda economizar um byteFalse
não é permitido para0
, em vez de alterarg(f(l,n+1),n+1)
a1*g(f(l,n+1),n+1)
, alterá-lo para+g(f(l,n+1),n+1)
h=
contagem de bytes