Tarefa
Dada a entrada N, gere e produza uma grade NxN em que cada linha, coluna e as duas diagonais contenham os números de 1 a N
(ou 0 a N
-1 se for mais fácil).
Entrada
A entrada é um número inteiro positivo N
. Representa o número de colunas e linhas na grade. Para esse problema, você pode assumir N
que o tamanho é razoável 4 ≤ N ≤ 8
ou ( 1 ≤ N ≤ 8
se você optar pelo bônus abaixo).
Saída
A saída será a grade N
× N
. Na grade, cada linha contém apenas os números 1 a N
, cada coluna contém apenas os números 1 a N
e as duas diagonais de comprimento N
(a de (0,0)
a (N-1,N-1)
e a de (0,N-1)
a (N-1, 0)
) contêm apenas os números de 1 a N
. Você pode usar os números de 0 a N−1
. Para cada uma delas N
, existem muitas soluções possíveis, você só precisa imprimir a primeira que encontrar. Você não precisa imprimir espaços entre os números.
Restrições
Seu código deve ser capaz de produzir resultados repetidamente para N >= 7
. Ou seja, se você é capaz de executar e obter uma solução a N = 7
partir do seu código a cada vez, você é bom. Em termos de um limite absoluto, seu código deve ser resolvido N = 7
em menos de 10 minutos cada vez que você o executar (ou seja, se você depende de números aleatórios, na pior das hipóteses, seu código ainda deve terminar em menos de 10 minutos por N = 7
) .
Exemplos
Entrada:
4
Uma saída possível:
1 2 3 4 3 4 1 2 4 3 2 1 2 1 4 3
Entrada:
5
Uma saída possível:
1 2 3 4 5 5 3 1 2 4 2 5 4 3 1 4 1 2 5 3 3 4 5 1 2
Entrada:
8
Uma saída possível:
1 2 3 4 5 6 7 8 2 3 1 5 4 8 6 7 4 1 2 3 7 5 8 6 6 4 7 8 1 2 3 5 7 5 8 2 6 3 4 1 5 8 4 6 2 7 1 3 8 7 6 1 3 4 5 2 3 6 5 7 8 1 2 4
Pontuação
Isso é código-golfe , portanto o código mais curto em bytes vence, com uma exceção. Para entradas, N = 2, 3
não há soluções válidas. Se o seu código puder lidar com isso (execute até a conclusão sem gerar nada para esses casos ou gerar uma string vazia) e ainda manipule N = 1
(produza 1
para ele), retire 20% da sua contagem de bytes.
fonte
N
.N = 1, 5 or 7
Porém, este código JavaScript funciona se ajudar alguém:for(o="",y=N;y--;o+="\n")for(x=N;x--;)o+=(((N-y)*2+x)%N)+1
N = 1
caso: as respostas que visam o bônus devem retornar1
, não a sequência vazia.Respostas:
Python 3,
275260 bytes * 0,8 =220208 bytesAbordagem recursiva / backtracking.
R
é a função recursiva,l
é a coluna,w
é a linha,K
é a próxima entrada.Eu escolhi colocá-lo em uma matriz 1d e imprimi-lo no final para simplificar os índices.
Versão não destruída:
fonte
Funciton não competitiva
ATUALIZAR! Melhoria maciça de desempenho!n = 7 agora é concluído em menos de 10 minutos! Veja a explicação na parte inferior!
Foi divertido escrever isso. Este é um solucionador de força bruta para esse problema escrito em Funciton. Alguns factóides:
3 2 1 0
e não na linha superior0 1 2 3
.0
(a única solução) para n = 1.Sem mais delongas:
Explicação da primeira versão
A primeira versão levou cerca de uma hora para resolver n = 7. O seguinte explica principalmente como essa versão lenta funcionou. Na parte inferior, explicarei as alterações que fiz para reduzir para menos de 10 minutos.
Uma excursão em pedaços
Este programa precisa de bits. Ele precisa de muitos bits, e precisa deles nos lugares certos. Programadores de funções experientes já sabem que se você precisar de n bits, poderá usar a fórmula
que em Funciton pode ser expresso como
Ao fazer minha otimização de desempenho, ocorreu-me que eu posso calcular o mesmo valor muito mais rapidamente usando esta fórmula:
Espero que você me perdoe por não ter atualizado todos os gráficos de equação neste post.
Agora, digamos que você não queira um bloco contíguo de bits; na verdade, você quer n bits em intervalos regulares a cada k- ésimo bit, assim:
A fórmula para isso é bastante direta quando você a conhece:
No código, a função
Ӝ
toma valores de n e k e calcula esta fórmula.Acompanhar os números usados
Existem n ² números na grade final e cada número pode ter qualquer um dos n valores possíveis. Para acompanhar quais números são permitidos em cada célula, mantemos um número que consiste em n ³ bits, no qual um bit é definido para indicar que um valor específico é obtido. Inicialmente, esse número é 0, obviamente.
O algoritmo começa no canto inferior direito. Depois de "adivinhar" o primeiro número é um 0, precisamos acompanhar o fato de que o 0 não é mais permitido em nenhuma célula na mesma linha, coluna e diagonal:
Para esse fim, calculamos os quatro valores a seguir:
Linha atual: precisamos de n bits a cada n- ésimo bit (um por célula) e, em seguida, alteramos para a linha atual r , lembrando que cada linha contém n ² bits:
Coluna atual: precisamos de n bits a cada n² -ésimo bit (um por linha) e, em seguida, mudamos para a coluna atual c , lembrando que cada coluna contém n bits:
Diagonal para a frente: precisamos de n bits a cada ... (você prestou atenção? Rápido, resolva isso!) ... n ( n +1) -simo bit (bom trabalho!), Mas apenas se estivermos realmente ligados a diagonal para a frente:
Diagonal para trás: duas coisas aqui. Primeiro, como sabemos se estamos na diagonal para trás? Matematicamente, a condição é c = ( n - 1) - r , que é a mesma que c = n + (- r - 1). Ei, isso lembra alguma coisa? É isso mesmo, é o complemento de dois, para que possamos usar a negação bit a bit (muito eficiente no Funciton) em vez do decremento. Segundo, a fórmula acima pressupõe que queremos que o bit menos significativo seja definido, mas na diagonal reversa não, então temos que alterá-lo ... você sabe? ... Isso mesmo, n ( n - 1).
Este também é o único onde potencialmente dividimos por 0 se n = 1. No entanto, o Funciton não se importa. 0 ÷ 0 é apenas 0, você não sabe?
No código, a função
Җ
(a inferior) pega n e um índice (do qual calcula r e c por divisão e restante), calcula esses quatro valores eor
os reúne.O algoritmo de força bruta
O algoritmo de força bruta é implementado por
Ӂ
(a função na parte superior). Leva n (o tamanho da grade), índice (onde atualmente estamos colocando um número na grade) e obtido (o número com n ³ bits nos dizendo quais números ainda podemos colocar em cada célula).Esta função retorna uma sequência de strings. Cada string é uma solução completa para a grade. É um solucionador completo; retornaria todas as soluções, se você permitir, mas as retornará como uma sequência avaliada preguiçosamente.
Se o índice atingiu 0, preenchemos com êxito a grade inteira, portanto retornamos uma sequência contendo a sequência vazia (uma solução única que não cobre nenhuma das células). A string vazia é
0
, e usamos a função de biblioteca⌑
para transformá-la em uma sequência de elemento único.A verificação descrita em melhoria de desempenho abaixo acontece aqui.
Se o índice ainda não atingiu 0, diminuímos em 1 para obter o índice no qual agora precisamos colocar um número (chame ix ).
Usamos
♫
para gerar uma sequência lenta contendo os valores de 0 a n - 1.Em seguida, usamos
ɓ
(ligação monádica) com um lambda que faz o seguinte na ordem:0
(sequência vazia).Җ
para calcular os bits correspondentes à linha, coluna e diagonal (s) atuais. Desloque-o por i e depoisor
para tomado .Ӂ
para recuperar todas as soluções para as células restantes, passando a nova tomada e a ix decrementada . Isso retorna uma sequência de cadeias incompletas; cada sequência possui caracteres ix (a grade é preenchida até o índice ix ).ɱ
(mapa) para percorrer as soluções assim encontradas e use‼
para concatenar i ao final de cada uma. Acrescente uma nova linha se o índice for múltiplo de n , caso contrário, um espaço.Gerando o resultado
O programa principal chama
Ӂ
(o forçador bruto) com n , índice = n ² (lembre-se de preencher a grade para trás) e tomado = 0 (inicialmente nada é tomado). Se o resultado for uma sequência vazia (nenhuma solução encontrada), imprima a sequência vazia. Caso contrário, imprima a primeira string na sequência. Observe que isso significa que ele avaliará apenas o primeiro elemento da sequência, e é por isso que o solucionador não continua até encontrar todas as soluções.Melhoria de desempenho
(Para quem já leu a versão antiga da explicação: o programa não gera mais uma sequência de sequências que precisa ser transformada separadamente em uma sequência de saída; apenas gera uma sequência de sequências diretamente. Editei a explicação de acordo . Mas essa não foi a principal melhoria. Aí vem.)
Na minha máquina, o exe compilado da primeira versão demorou quase exatamente 1 hora para resolver n = 7. Isso não estava dentro do prazo especificado de 10 minutos, então não descansei. (Bem, na verdade, a razão pela qual eu não descansei foi porque eu tinha essa ideia de como acelerar bastante.)
O algoritmo, conforme descrito acima, interrompe sua pesquisa e retorna sempre que encontra uma célula na qual todos os bits do número obtido são definidos, indicando que nada pode ser colocado nessa célula.
No entanto, o algoritmo continuará a preencher futilmente a grade até a célula na qual todos esses bits estão definidos. Seria muito mais rápido se pudesse parar assim que qualquer célula ainda a ser preenchida já tiver todos os bits configurados, o que já indica que nunca poderemos resolver o restante da grade, independentemente dos números que inserimos isto. Mas como você verifica com eficiência se alguma célula possui seus n bits definidos sem passar por todos eles?
O truque começa adicionando um único bit por célula ao número obtido . Em vez do que foi mostrado acima, agora fica assim:
Em vez de n ³, agora existem n ² ( n + 1) bits nesse número. A função que preenche a linha / coluna / diagonal atual foi alterada de acordo (na verdade, completamente reescrita para ser sincera). Porém, essa função ainda preencherá apenas n bits por célula; portanto, o bit extra que acabamos de adicionar sempre será
0
.Agora, digamos que estamos no meio do cálculo, apenas colocamos um
1
na célula do meio e o número obtido é mais ou menos assim:Como você pode ver, a célula superior esquerda (índice 0) e a célula esquerda central (índice 10) agora são impossíveis. Como determinamos isso com mais eficiência?
Considere um número no qual o 0º bit de cada célula está definido, mas apenas até o índice atual. É fácil calcular esse número usando a fórmula familiar:
O que teríamos se adicionássemos esses dois números?
O resultado é:
Como você pode ver, a adição transborda para o bit extra que adicionamos, mas apenas se todos os bits para essa célula estiverem definidos! Portanto, tudo o que resta a fazer é mascarar esses bits (mesma fórmula acima, mas << n ) e verificar se o resultado é 0:
Se não for zero, a grade é impossível e podemos parar.
fonte
Haskell, 790 * 0,80 = 632 bytes
Notei que este problema é muito semelhante ao sudoku. Lembro-me de um antigo solucionador de sudoku que escrevi em Haskell com base em nesse outro em Python. Este é o meu primeiro post ou tentativa de golfe com código.
Isso cumpre o bônus porque retorna
Nothing
paran=2,3
eJust <result>
paran>=4
, onde<result>
é uma matriz 2D de valores integrais.Veja aqui o intérprete online. Na verdade, esse código é mais longo que o da publicação, porque o intérprete on-line possui requisitos mais rígidos sobre o que forma um programa completo (as regras dizem que um envio pode ser uma função). Este envio recebe entrada como argumento de função.
fonte
c=[1..r]
, para poder usá-lo emo
ew
. b)minimumBy(\(a,_)(b,_)->compare a b)[...]
éhead$sortOn fst[...]
. c) ov
nov=g0!s
é usada apenas uma vez, por isso não defini-lo em tudo:l=length$g0!s
. d) você ainda possui alguns nomes de parâmetro de duas letras. e) substituaTrue
por1<2
eFalse
com2<1
. f)and[case g0!s of{[_]->True;_->False}|s<-u]
éall((==1).length.(g0!))u
.(&)m k=
pode ser definida infix:m&k=
. h)not(d
elem(g0!p))
énotElem d$g0!p
. i)concat(...)
éid=<<(...)
. j) use um operador infix parah
, por exemploas%bs=
.``like`this``
!Pitão, 41 bytes
Força bruta ftw!
Como isso basicamente continua tentando embaralhar aleatoriamente até que funcione (bem, continua tentando
n * [shuffle(range(n))]
), leva muito, muito tempo. Aqui estão alguns testes para dar uma idéia de quanto tempo leva:Isso é apenas 4x4, e roda em pouco menos de meio segundo. Na verdade, estou trapaceando porque esse é o melhor de alguns ensaios - a maioria deles demora mais de um segundo ou dois.
Ainda estou para obter um timing em 5x5 (ele foi concluído uma vez, mas isso estava em um REPL e eu não estava no momento).
Observe que a regra para o prazo só foi editada na pergunta após a publicação desta resposta.
fonte
SWI-Prolog, 326 * 0,80 = 260,8 bytes
Edit: salvou 16 bytes graças a @Mat
Uso
Ligue
a(5).
para o seu intérprete paraN=5
. Isso retornafalse
paraN=2
ouN=3
.Como ele usa a biblioteca CLPFD, isso não é força bruta pura. Este programa pode encontrar uma solução para
N=20
em 15 segundos no meu computador.Ungolfed + explicações:
Isso basicamente funciona como um solucionador de Sudoku, exceto que as restrições de blocos são substituídas pelas restrições de diagonais.
fonte
maplist(maplist(all_distinct), [R,C,D,E])
[R,C,[D,E]]
, porém, porqueE
eD
são listas simples.N=20
CJam, 87 bytes - bônus de 20% = 69,6 bytes
Codifica as respostas. Contém alguns imprimíveis. Trabalhos para
N = 1
atravésN = 8
.Basicamente, cada linha nessa cadeia misteriosa contém índices na lista de permutações de
range(N)
, codificados como caracteres Unicode.=:i0+\,m!f=
indexa na lista de permutações, adicionando um 0 ao final da lista de índices primeiro, representando a linha inferior0 1 2 ... N-1
. PoisN < 4
, a matriz 2D resultante não faz sentido.`1LL]
cria uma lista[N, pretty output, 1, "", ""]
. Em seguida,(4e<=
aparece o primeiro elemento dessa listaN
e recupera omin(N, 4) % 4
elemento th do restante. PoisN >= 4
essa é a saída e, caso contrário, são as saídas de casos especiais para os três primeiros casos.Experimente aqui .
fonte
C ++,
672 * 0,80645 * 0,80 = 516 bytesExperimente online aqui
Como algumas respostas já foram postadas, pensei em publicar a versão em golf do código que usei para gerar a saída para os exemplos. Esta é minha primeira vez respondendo a código de golfe , para que todos os comentários sejam bem-vindos. :)
Ungolfed + explicações:
Essencialmente, o código está forçando brutalmente uma solução. Começa na primeira linha, com 0. Começa no primeiro ponto, se esse ponto passar em todas as verificações, passará para o próximo número. Se preencher a linha, passa para a próxima linha. Se isso for feito em todas as linhas, isso significa que uma solução foi encontrada. Se o ponto não passar em todas as verificações, ele passa para o próximo ponto. Se a linha for concluída, ela retornará, pois um número em uma das linhas anteriores impede que uma solução seja possível.
fonte
if (x[r][p]) return f(c+1,r);
. Estou trabalhando para reduzi-lo.Clojure,
(215 + 258) * 0,8 = 378,4(174 + 255) * 0,8 = 343,2Dividido em duas partes: contagem de erros
S
e uma função anônima que faz a otimização real via pesquisa Tabu .Atualização: mais curto
S
(conta valores distintos dentro dos grupos), estado inicial menos ideal (sem reprodução aleatória).Benchmarks de núcleo único (em milissegundos) por 4, 5, 6 e 7 executados 3 vezes:
Original:
Eu gostaria que
S
fosse mais curto, mas como conta apenas ocorrências de mais de uma / partição, o critério de parada é simples(= s 0)
.Muitos ciclos de CPU são desperdiçados para trocas não úteis, por exemplo, não melhora a pontuação se você trocar
2
com2
, e você não precisa de números de swap entre linhas como todos eles têm valores distintos para começar.Benchmarks com o Intel 6700K (em milissegundos):
Multithread com
pmap
:fonte