Para uma imagem N por N , encontre um conjunto de pixels de forma que nenhuma distância de separação esteja presente mais de uma vez. Ou seja, se dois pixels são separados por uma distância d , eles são os únicos dois pixels separados por exatamente d (usando distância euclidiana ). Observe que d não precisa ser inteiro.
O desafio é encontrar um conjunto maior desse que qualquer outro.
Especificação
Nenhuma entrada é necessária - para este concurso N será fixado em 619.
(Como as pessoas continuam perguntando - não há nada de especial no número 619. Ele foi escolhido para ser grande o suficiente para tornar improvável uma solução ideal e pequeno o suficiente para permitir que uma imagem N por N seja exibida sem que o Stack Exchange a reduza automaticamente. exibido em tamanho máximo de 630 por 630, e decidi ir com a maior prime que não exceda isso.)
A saída é uma lista separada por espaços de números inteiros.
Cada número inteiro na saída representa um dos pixels, numerados na ordem de leitura em inglês de 0. Por exemplo, para N = 3, os locais seriam numerados nesta ordem:
0 1 2
3 4 5
6 7 8
Você pode enviar informações de progresso durante a execução, se desejar, desde que a saída final da pontuação esteja facilmente disponível. Você pode enviar para STDOUT ou para um arquivo ou o que for mais fácil de colar no Juiz de snippets de pilha abaixo.
Exemplo
N = 3
Coordenadas escolhidas:
(0,0)
(1,0)
(2,1)
Saída:
0 1 5
Ganhando
A pontuação é o número de locais na saída. Das respostas válidas que têm a pontuação mais alta, o mais cedo a publicar resultados com essa pontuação vence.
Seu código não precisa ser determinístico. Você pode postar sua melhor saída.
Áreas relacionadas à pesquisa
(Obrigado a Abulafia pelos links Golomb)
Embora nenhum deles seja o mesmo que esse problema, ambos são semelhantes em conceito e podem fornecer idéias sobre como abordar isso:
- Régua de Golomb : o caso unidimensional.
- Retângulo Golomb : uma extensão bidimensional da régua Golomb. Uma variante do caso NxN (quadrado) conhecida como matriz Costas é resolvida para todos os N.
Observe que os pontos necessários para esta pergunta não estão sujeitos aos mesmos requisitos que um retângulo Golomb. Um retângulo de Golomb se estende do caso unidimensional, exigindo que o vetor de cada ponto um para o outro seja único. Isso significa que pode haver dois pontos separados por uma distância de 2 na horizontal e também dois pontos separados por uma distância de 2 na vertical.
Para esta pergunta, é a distância escalar que deve ser única, portanto não pode haver uma separação horizontal e vertical de 2. Toda solução para essa pergunta será um retângulo de Golomb, mas nem todo retângulo de Golomb será uma solução válida para essa questão.
Limites superiores
Dennis, prestativamente, apontou no bate-papo que 487 é um limite superior na pontuação e deu uma prova:
De acordo com meu código CJam (
619,2m*{2f#:+}%_&,
), existem 118800 números únicos que podem ser escritos como a soma dos quadrados de dois números inteiros entre 0 e 618 (ambos inclusive). n pixels requerem n (n-1) / 2 distâncias únicas entre si. Para n = 488, isso dá 118828.
Portanto, existem 118.800 comprimentos diferentes possíveis entre todos os pixels em potencial na imagem, e a colocação de 488 pixels em preto resultaria em 118.828 comprimentos, o que torna impossível que todos sejam únicos.
Eu ficaria muito interessado em saber se alguém tem uma prova de um limite superior mais baixo do que isso.
Entre os melhores
(Melhor resposta de cada usuário)
Juiz do snippet de pilha
fonte
Respostas:
Python 3,
135136137Encontrado usando um algoritmo ganancioso que, em cada estágio, escolhe o pixel válido cujo conjunto de distâncias para os pixels escolhidos se sobrepõe menos ao de outros pixels.
Especificamente, a pontuação é
e o pixel com a menor pontuação é escolhido.
A busca é iniciada com o ponto
10
(ie(0, 10)
). Esta parte é ajustável, portanto, começar com pixels diferentes pode levar a resultados melhores ou piores.É um algoritmo bastante lento, então estou tentando adicionar otimizações / heurísticas e, talvez, algum retorno. PyPy é recomendado para velocidade.
Qualquer pessoa que tente criar um algoritmo deve testar
N = 10
, para o qual eu tenho 9 (mas isso exigiu muitos ajustes e tentativas de diferentes pontos iniciais):Código
fonte
N=10
e há muitos layouts distintos com 9 pts, mas é o melhor que você pode fazer.SWI-Prolog, pontuação 131
Um pouco melhor do que a resposta inicial, mas acho que isso fará as coisas começarem um pouco mais. O algoritmo é o mesmo que a resposta do Python, exceto pelo fato de tentar pixels de maneira alternativa, começando com o pixel superior esquerdo (pixel 0), depois o pixel inferior direito (pixel 383160), depois o pixel 1 e o pixel 383159 etc.
Entrada:
a(A).
Saída:
Imagem do snippet de pilha
fonte
Haskell -
115130131135136Minha inspiração foi a Peneira de Eratóstenes e, em particular, A Peneira Genuína de Eratóstenes , um artigo de Melissa E. O'Neill da Harvey Mudd College. Minha versão original (que considerou os pontos na ordem do índice) peneirou os pontos extremamente rapidamente; por algum motivo, não me lembro, decidi embaralhar os pontos antes de peneirá-los nesta versão (acho que apenas para facilitar a geração de respostas diferentes usando uma nova semente no gerador aleatório). Como os pontos não estão mais em nenhum tipo de ordem, não há mais nenhuma peneira e, como resultado, leva alguns minutos apenas para produzir essa resposta única de 115 pontos. Um nocaute
Vector
provavelmente seria uma escolha melhor agora.Portanto, com esta versão como um ponto de verificação, vejo duas ramificações, retornando ao algoritmo “Genuine Sieve” e aproveitando a mônada List para escolha ou trocando as
Set
operações por equivalentesVector
.Edit: Então, para a versão de trabalho dois, eu virei de volta para o algoritmo de peneira, aprimorei a geração de “múltiplos” (eliminando índices ao encontrar pontos nas coordenadas inteiras em círculos com raio igual à distância entre dois pontos, semelhante à geração de múltiplos primos ) e fazendo algumas melhorias constantes no tempo, evitando alguns recálculos desnecessários.
Por alguma razão, não posso recompilar com a criação de perfis ativada, mas acredito que o maior gargalo agora é o retrocesso. Acho que explorar um pouco de paralelismo e simultaneidade produzirá acelerações lineares, mas a exaustão da memória provavelmente me trará uma melhoria de 2x.
Edit: Version 3 meandered um pouco, eu primeiro experimentei com uma heurística em tomar os próximos 𝐧 índices (depois de peneirar de escolhas anteriores) e escolher o que produziu o próximo conjunto de nocaute mínimo. Como acabou sendo muito lento, voltei a um método de força bruta para todo o espaço de pesquisa. Uma idéia para ordenar os pontos à distância de alguma origem veio a mim e levou a uma melhoria em um único ponto (no tempo em que minha paciência durou). Esta versão escolhe o índice 0 como a origem, pode valer a pena tentar o ponto central do plano.
Editar: peguei 4 pontos reordenando o espaço de pesquisa para priorizar os pontos mais distantes do centro. Se você está testando meu código,
135136 é realmente asegundaterceira solução encontrada. Edição rápida: esta versão parece mais provável de continuar sendo produtiva se deixada em execução. Suspeito que eu possa empatar aos 137 anos e ficar sem paciência esperando por 138.Uma coisa que notei (que pode ser útil para alguém) é que, se você definir o ponto ordenado no centro do plano (ou seja, remover
(d*d -)
deoriginDistance
) a imagem formada parecerá um pouco com uma espiral esparsa.Saída
fonte
d
minimiza o número de outros pontos excluídos da consideração, traçando círculos de raiod
com centros dos dois pontos escolhidos, onde o perímetro toca apenas três outras coordenadas inteiras (giros de 90, 180 e 270 graus) o círculo) e a linha de bissecção perpendicular que não cruza coordenadas inteiras. Portanto, cada novo ponton+1
excluirá6n
outros pontos da consideração (com a escolha ideal).Python 3, pontuação 129
Este é um exemplo de resposta para começar.
Apenas uma abordagem ingênua, percorrendo os pixels em ordem e escolhendo o primeiro pixel que não causa uma distância de separação duplicada, até que os pixels acabem.
Código
Saída
Imagem do snippet de pilha
fonte
Python 3, 130
Para comparação, aqui está uma implementação de backtracker recursivo:
Ele encontra a seguinte solução de 130 pixels rapidamente antes de começar a engasgar:
Mais importante, estou usando-o para verificar soluções para casos pequenos. Pois
N <= 8
, o ideal são:Entre parênteses estão os primeiros ideais lexicográficos.
Não confirmado:
fonte
Scala, 132
Digitaliza da esquerda para a direita e de cima para baixo como a solução ingênua, mas tenta iniciar em diferentes locais de pixels.
Saída
fonte
Python, 134
132Aqui está um simples que seleciona aleatoriamente parte do espaço de pesquisa para cobrir uma área maior. Ele itera os pontos na distância de uma ordem de origem. Ele pula pontos que estão à mesma distância da origem e sai cedo se não puder melhorar o melhor. É executado indefinidamente.
Encontra rapidamente soluções com 134 pontos:
3097 3098 2477 4333 3101 5576 1247 9 8666 8058 12381 1257 6209 15488 6837 21674 19212 26000 24783 1281 29728 33436 6863 37767 26665 14297 4402 43363 50144 52624 18651 9996 58840 42792 6295 69950 44351533 106444354154333 113313 88637 122569 11956 36098 79401 61471 135610 31796 4570 150418 57797 4581 125201 151128 115936 165898 127697 162290 33091 20098 189414 187620 186440 91290 206766 35619 69033 351 186511 28902735271527445415415445645435 249115 21544 95185 231226 54354 104483 280665 518 147181 318363 1793 248609 82260 52568 365227 361603 346849 331462 69310 90988 341446 229599 277828 382837 339014 323612 365040 269883 307597 3746347 316282
Para os curiosos, aqui estão alguns pequenos N de força bruta:
fonte
Fantom 96
Eu usei um algoritmo de evolução, basicamente adicione k pontos aleatórios de cada vez, faça isso para j conjuntos aleatórios diferentes, depois escolha o melhor e repita. Resposta bastante terrível no momento, mas é executada com apenas 2 filhos por geração, por uma questão de velocidade, o que é quase aleatório. Vou jogar um pouco com os parâmetros para ver como vai ser, e provavelmente preciso de uma função de pontuação melhor do que o número de vagas livres restantes.
Saída
fonte
Python 3, 119
Não lembro mais por que nomeei essa função
mc_usp
, embora suspeite que tenha algo a ver com as cadeias de Markov. Aqui, publico meu código que executei com o PyPy por cerca de 7 horas. O programa tenta criar 100 conjuntos diferentes de pixels, escolhendo aleatoriamente os pixels até verificar cada pixel da imagem e retornar um dos melhores conjuntos.Em outra nota, em algum momento, deveríamos realmente tentar encontrar um limite superior para
N=619
488, porque, a partir das respostas aqui, esse número é muito alto. O comentário de Rowan Blush sobre como cada novo ponton+1
pode potencialmente remover6*n
pontos com a escolha ideal parecia uma boa idéia. Infelizmente, após a inspeção da fórmulaa(1) = 1; a(n+1) = a(n) + 6*n + 1
, ondea(n)
é o número de pontos removidos após adicionarn
pontos ao nosso conjunto, essa ideia pode não ser a melhor opção. Verificando quandoa(n)
é maior queN**2
,a(200)
sendo maior que619**2
parece promissor, masa(n)
maior que10**2
éa(7)
e provamos que 9 é o limite superior real paraN=10
. Vou mantê-lo informado enquanto tento melhorar o limite superior, mas todas as sugestões são bem-vindas.Para a minha resposta. Primeiro, meu conjunto de 119 pixels.
Segundo, meu código, que escolhe aleatoriamente um ponto de partida de um octante do quadrado de 619x619 (já que o ponto de partida é igual em rotação e reflexão) e depois todos os outros pontos do resto do quadrado.
fonte