Introdução
Há um cobrador de impostos que tem problemas para gerenciar os impostos de seu reino: os registros históricos queimaram em um grande incêndio.
Ele quer descobrir quantos passados possíveis poderiam existir em termos de onde o dinheiro atual foi herdado. Felizmente, seu reino é muito simples.
O reino pode ser modelado por uma matriz booleana 2D, onde l
representa alguém que herdou dinheiro e O
representa alguém que não herdou . Por exemplo:
l O l l
O O O l
l O l O
O O O l
(Sempre será um retângulo)
Na próxima geração, o reino é menor (os lobos são fortes!).
A próxima geração ficaria assim, sobreposta à geração anterior ( x
é um espaço reservado para um descendente na próxima geração)
l O l l
x x x
O O O l
x x x
l O l O
x x x
O O O l
Um descendente olhar para os antepassados que são diretamente em torno deles (Assim, o canto superior esquerdo x
verá { l
, O
, O
, O
}, chamado de bairro retangular Unaligned )
Se apenas um ancestral herdou dinheiro, o descendente herdará dinheiro deles. Se mais de um ancestral herdou dinheiro, eles brigam e o descendente acaba não herdando dinheiro. Se ninguém herdou dinheiro, o descendente não herdará dinheiro.
(Mais de um descendente pode herdar de um ancestral)
Portanto, a próxima geração seria assim:
l l O
l l O
l l O
Desafio
Entrada
O estado atual da geração, como uma matriz de matrizes de dois valores distintos, em que as matrizes internas têm o mesmo comprimento.
Por exemplo, para o exemplo acima, pode ser:
[
[True, True, False],
[True, True, False],
[True, True, False]
]
Resultado
Um número inteiro que representa o número de gerações anteriores exclusivas em que a próxima geração é a entrada.
Você pode supor que a resposta sempre será menor que 2 ^ 30 - 1. (ou 1073741823).
A geração anterior seria chamada de "pré-imagem" e esse desafio seria contar as pré-imagens .
Pontuação
Esse é um desafio de código mais rápido ; portanto, cada envio será testado no meu computador, e o envio que demorar menos tempo será o vencedor.
Exemplo de entrada e saída
(Onde 1
está um descendente que herdou dinheiro e 0
é um descendente que não herdou dinheiro)
Entrada:
[[1, 0, 1],
[0, 1, 0],
[1, 0, 1]]
Resultado:
4
Entrada:
[[1, 0, 1, 0, 0, 1, 1, 1],
[1, 0, 1, 0, 0, 0, 1, 0],
[1, 1, 1, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 0, 0, 1, 0],
[1, 0, 1, 0, 0, 1, 1, 1]]
Resultado:
254
Entrada:
[[1, 1, 0, 1, 0, 1, 0, 1, 1, 0],
[1, 1, 0, 0, 0, 0, 1, 1, 1, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 1, 1, 0, 0]]
Resultado:
11567
fonte
Respostas:
C ++ usando a biblioteca BuDDy
Parecia uma boa desculpa para brincar com diagramas de decisão binária . O reino é convertido em uma grande fórmula booleana, na qual temos que contar o número de maneiras pelas quais ele pode ser satisfeito. Isso pode (às vezes) ser feito com mais eficiência do que parece.
O reino deve ser dado como um programa constante como uma matriz plana e com dimensões explicitamente dadas. (Uma boa entrada é deixada como uma execução para o leitor :-)
Aqui está o código embaraçosamente simples:
Para compilar com o debian 8 (jessie), instale
libbdd-dev
e façag++ -std=c++11 -o hist hist.cpp -lbdd
. (As opções de otimização quase não fazem diferença porque o trabalho real é feito na biblioteca.)Grandes exemplos podem levar a mensagens sobre coleta de lixo. Eles podem ser suprimidos, mas eu prefiro vê-los.
bdd_satcount
retorna adouble
, mas isso é bom o suficiente para o intervalo esperado de resultados. A mesma técnica de contagem é possível com números inteiros exatos (grandes).O código está otimizado para
ROWS<COLS
. Se você tiver muito mais linhas do que colunas, pode ser uma boa ideia transpor a matriz.fonte
Python 2.7
Esta é apenas uma primeira tentativa ingênua. Não é particularmente rápido, mas está correto.
A primeira observação é que cada célula depende exatamente de quatro células na geração anterior. Podemos representar essas quatro células como um número de 4 bits (0-15). De acordo com as regras, se exatamente uma célula vizinha da geração anterior for
1
, então uma determinada célula na geração atual será1
, caso contrário, será0
. Esses correspondem aos poderes de dois, a saber[1, 2, 4, 8]
,. Quando os quatro ancestrais são representados como um número de 4 bits, qualquer outro número resultará em um0
na geração atual. Com essas informações, ao ver uma célula na geração atual, podemos reduzir as possibilidades do bairro na geração anterior para uma das quatro ou uma das doze possibilidades, respectivamente.Eu escolhi representar o bairro da seguinte maneira:
onde 0 é o bit menos significativo e assim por diante.
A segunda observação é que, para duas células adjacentes na geração atual, os dois bairros da geração anterior se sobrepõem:
ou:
No caso horizontal, o
2
bairro da esquerda se sobrepõe ao3
bairro da direita e, da mesma forma,0
à esquerda e1
à direita. No caso vertical, a1
vizinhança da parte superior se sobrepõe à vizinhança3
da parte inferior e da mesma forma que0
na parte superior e2
na parte inferior.Essa sobreposição significa que podemos reduzir as possibilidades de bairros ainda não escolhidos com base no que já escolhemos. O código funciona da esquerda para a direita, de cima para baixo, em uma pesquisa recursiva em profundidade, para possíveis pré-imagens. O diagrama a seguir indica quais vizinhanças anteriores devemos considerar ao examinar as possíveis vizinhanças de uma célula atual:
Aqui está o código:
Para executá-lo:
fonte
O(<something>^n)
, eu acho.)