fundo
Considere uma cadeia de hastes (fechada), cada uma com comprimento inteiro. Quantos poliaminos distintos sem orifícios você pode formar com uma determinada corrente? Ou, em outras palavras, quantos polígonos diferentes que não se interceptam com lados alinhados ao eixo você pode formar com uma determinada cadeia?
Vejamos um exemplo. Considere uma corrente específica que consiste em 8 hastes de comprimento 1 e 2, que podemos representar como [1, 1, 2, 2, 1, 1, 2, 2]
. Até rotações e traduções, existem apenas 8 possíveis poliomatos (contamos diferentes reflexões):
Essa primeira haste é azul escuro e, em seguida, atravessamos o polígono no sentido anti-horário .
O senso de rotação não afeta o resultado no exemplo acima. Mas vamos considerar outra cadeia [3, 1, 1, 1, 2, 1, 1]
, que produz os seguintes 3 polioquinós:
Observe que não incluímos um reflexo do último poliomino, porque isso exigiria a rotação no sentido horário.
Se tivéssemos uma cadeia mais flexível do mesmo comprimento, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
poderíamos realmente formar ambas as reflexões entre alguns outros polioninos, totalizando 9:
O desafio
Dada a descrição de uma cadeia, como uma matriz ou similar, determine o número de poliomatos distintos que você pode formar (até rotações e translações) usando as hastes em ordem enquanto percorre o perímetro no sentido anti-horário.
Escreva um programa completo e inclua comandos para compilar (se aplicável) e executar seu código na linha de comando. Inclua também um link para um compilador / intérprete gratuito para o seu idioma.
Seu programa deve ler a entrada do STDIN. A primeira linha conterá um número inteiro M . As próximas M linhas serão casos de teste, cada um dos quais com uma lista de comprimentos de haste separados por espaço. Seu programa deve imprimir linhas M em STDOUT, cada uma das quais consiste em um único número inteiro - o número de poliomatos diferentes que podem ser formados.
Você deve usar apenas um único thread.
Seu programa não deve usar mais de 1 GB de memória a qualquer momento. (Esse não é um limite completamente estrito, mas monitorarei o uso da memória do executável e eliminarei qualquer processo que use consistentemente mais de 1 GB ou que atinja significativamente mais do que isso.)
Para evitar quantidades excessivas de pré-cálculo, seu código não deve exceder 20.000 bytes e você não deve ler nenhum arquivo.
Você também não deve otimizar para os casos de teste específicos escolhidos (por exemplo, codificando seus resultados). Se suspeitar que sim, reservo-me o direito de gerar novos conjuntos de benchmarks. Os conjuntos de testes são aleatórios; portanto, o desempenho do seu programa nesses deve ser representativo pelo desempenho em entradas arbitrárias. A única suposição que você pode fazer é que a soma dos comprimentos da haste seja uniforme.
Pontuação
Forneci conjuntos de referência para cadeias de N = 10, 11, ..., 20 hastes. Cada conjunto de testes contém 50 cadeias aleatórias com comprimentos entre 1 e 4, inclusive.
Sua pontuação principal é o maior N para o qual seu programa conclui todo o conjunto de testes em 5 minutos (na minha máquina, no Windows 8). O desempate será o tempo real gasto pelo seu programa nesse conjunto de testes.
Se alguém vencer o maior conjunto de testes, continuarei adicionando outros maiores.
Casos de teste
Você pode usar os seguintes casos de teste para verificar a correção da sua implementação.
Input Output
1 1 0
1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1 1 1 9
1 1 1 1 1 1 1 1 1 1 1 1 36
1 1 1 1 1 1 1 1 1 1 1 1 1 1 157
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 758
1 1 2 2 1 1 2 2 8
1 1 2 2 1 1 2 2 1 1 23
1 1 2 2 1 1 2 2 1 1 2 2 69
1 2 1 2 1 2 1 2 3
1 2 1 2 1 2 1 2 1 2 1 2 37
1 2 3 2 1 2 3 2 5
1 2 3 2 1 2 3 2 1 2 3 2 23
3 1 1 1 2 1 1 3
1 2 3 4 5 6 7 1
1 2 3 4 5 6 7 8 3
1 2 3 4 5 6 7 8 9 10 11 5
2 1 5 3 3 2 3 3 4
4 1 6 5 6 3 1 4 2
3 5 3 5 1 4 1 1 3 5
1 4 3 2 2 5 5 4 6 4
4 1 3 2 1 2 3 3 1 4 18
1 1 1 1 1 2 3 3 2 1 24
3 1 4 1 2 2 1 1 2 4 1 2 107
2 4 2 4 2 2 3 4 2 4 2 3 114
Você encontra um arquivo de entrada com estes aqui .
Entre os melhores
User Language Max N Time taken (MM:SS:mmm)
1. feersum C++ 11 19 3:07:430
2. Sp3000 Python 3 18 2:30:181
fonte
Respostas:
C ++ 11
Atualizações: adicionada a primeira linha
c
que sai mais cedo se a distância estiver muito longe da origem (que era o objetivo da variávelrlen
, mas eu esqueci de escrevê-la na primeira versão). Eu mudei para usar muito menos memória, mas com o custo do tempo. Agora resolve N = 20 em menos de 5 minutos para mim.Ajuntar com
fonte
#define
é thoPython 3 (com PyPy ) - N = 18
Corra com
./pypy <filename>
.Esta é a implementação de referência que escrevi ao discutir a questão com Martin. Não foi feito com a velocidade em mente e é bastante hacky, mas deve fornecer uma boa base para iniciar as coisas.
N = 18 leva cerca de 2,5 minutos no meu laptop modesto.
Algoritmo
As rotações são verificadas convertendo cada forma em uma série de
F
para a frente,A
para a curva anti-C
horária e para a rotação horária em cada ponto da rede no limite da forma - eu chamo isso de uma sequência angular . Duas formas são rotacionalmente idênticas se suas seqüências de ângulos forem permutações cíclicas. Em vez de sempre verificar isso comparando duas seqüências de ângulos diretamente, quando encontramos uma nova forma, convertemos em uma forma canônica antes de armazenar. Quando temos um novo candidato, convertemos para a forma canônica e verificamos se já o temos (explorando o hash, em vez de iterar por todo o conjunto).A sequência de ângulos também é usada para verificar se a forma é formada no sentido anti-horário, certificando-se de que o número de
A
s exceda o número deC
s por 4.A auto-interseção é verificada ingenuamente, armazenando todos os pontos da treliça nos limites da forma e verificando se um ponto é visitado duas vezes.
O algoritmo principal é simples, colocando a primeira haste à direita e tentando todas as possibilidades para as hastes restantes. Se as hastes atingirem um ponto muito distante da origem (ou seja, a soma dos comprimentos restantes da haste for menor que a distância de Manhattan do ponto da origem), paramos prematuramente a busca nessa subárvore.
Atualizações (mais recentes primeiro)
fonte