Maximizar a diferença ao quadrado


19

Considere uma permutação dos valores inteiros de 1a N. Por exemplo, este exemplo para N = 4:

[1, 3, 4, 2]

Consideraremos que esta lista é cíclica, de modo que 1e 2é tratada como adjacente. Uma quantidade que podemos calcular para essa lista é a diferença total quadrática dos valores adjacentes:

(1-3)² + (3-4)² + (4-2)² + (2-1)² = 10

Sua tarefa é encontrar uma permutação que maximize essa quantidade, dado um número inteiro positivo N. No caso do N = 4exemplo acima, não é o ideal (na verdade, é mínimo). Podemos alcançar uma diferença quadrática total 18com a seguinte permutação (bem como várias outras):

[1, 4, 2, 3]

Seu algoritmo deve ser executado em tempo polinomial (de N). Em particular, você não pode simplesmente calcular a diferença quadrática total de todas as permutações.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

A saída pode estar em qualquer formato conveniente, inequívoco, de lista simples ou de seqüência de caracteres. Você pode optar por retornar uma lista com valores de 0para em N-1vez de 1para N.

Aplicam-se as regras padrão de .

Dados de teste

Existe uma boa solução analítica para esse problema. Por exemplo, todas as soluções válidas para N = 10são equivalentes à seguinte lista (até turnos cíclicos e reversão):

[7, 5, 6, 4, 8, 2, 10, 1, 9, 3]

Eu não quero revelar muito além disso (embora seja provavelmente o suficiente para descobrir o padrão), então, em vez de dar mais exemplos, você pode verificar se seus resultados têm as seguintes diferenças quadráticas totais para um dado N:

N    Total squared difference

1                         0
2                         2
3                         6
4                        18
5                        36
6                        66
7                       106
8                       162
9                       232
10                      322
33                    11936
100                  333202
333                12308236
1000              333332002

Essa é a entrada A064842 da OEIS (que também contém uma referência a um papel com uma solução para esse desafio, se você estiver preso).

Respostas:


7

Geléia, 24 21 15 14 10 9 bytes

RUĖµ«/€ị"

Para calcular a diferença total quadrática, acrescente µ_ṙ1$²Sao código. Experimente online!

fundo

Uma maneira de gerar uma permutação com diferença quadrática maximizada é levar os números inteiros 1 a n em ordem crescente e trocar o segundo da esquerda com o segundo da direita, o quarto da esquerda com o quarto da direita, e assim adiante até nos encontrarmos no meio.

Por exemplo, para n = 8, 9 , temos

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
  ^   ^ ^   ^            ^   ^   ^   ^

(circunflexos marcam números inteiros a serem trocados), o que resulta em

1 7 3 5 4 6 2 8        1 8 3 6 5 4 7 2 9

depois de trocar.

Uma maneira de obter esses swaps, independentemente da paridade de n , é a seguinte.

Comece escrevendo os números inteiros em ordem crescente e decrescente, um abaixo do outro.

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

Para cada par de números inteiros, calcule o mínimo do par. Isso indica a distância até a borda mais próxima, ou seja, o índice da esquerda ou da direita (o que for mais baixo).

1 2 3 4 5 6 7 8        1 2 3 4 5 6 7 8 9
8 7 6 5 4 3 2 1        9 8 7 6 5 4 3 2 1

1 2 3 4 4 3 2 1        1 2 3 4 5 4 3 2 1

Se o mínimo for ímpar, o número inteiro deve permanecer em seu lugar, portanto, selecionamos o da primeira linha; se for par, os números inteiros devem ser trocados; portanto, selecionamos o número da segunda linha.

1   3     6   8        1   3   5   7   9
  7   5 4   2            8   6   4   2

Esta é a saída desejada.

Como funciona

RUĖµ«/€ị"    Main link. Input: n

R            Range. Yields [1, ..., n].
 U           Upend. Yields [n, ..., 1].
  Ė          Enumerate. Yields p := [[1, n], [2, n-1], ... [n-1, 2], [n, 1]].

   µ         Begin a new, monadic chain. Argument: p
     /       Reduce...
      €        each pair of p...
    «          by minimum.
        "    For each minimum and the corresponding pair of p:
       ị       Select the element at that index.
            Indices are modular and 1-based in Jelly, so this selects the first
            element if the minimum is odd, and the second one if it is even.

6

JavaScript (ES6), 52 bytes

n=>[...Array(n)].map((_,i)=>(i<n/2|n%2)^i%2?i+1:n-i)

9 bytes salvos graças ao @Neil!

Explicação

Essa abordagem determina o número que deve estar no índice icom um comprimento em nvez de concatenar os resultados em uma matriz. Isso se baseia na seguinte observação (usando n = 7como exemplo):

  • Comece com o menor número à esquerda e o maior à direita: [ 1, 7 ]
  • Alterne a ordem para que o menor fique à direita e o mais alto à esquerda, aumente o mais baixo, diminua o mais alto e coloque-os no meio da matriz:[ 1, 6, 2, 7 ]
  • Repita até que a maior e a menor convergem: [ 1, 6, 3, 4, 5, 2, 7 ]

Os números mais alto e mais baixo podem ser facilmente expressos como n-ie i+1respectivamente.

var solution =

n=>
  [...Array(n)] // create an array of length n
  .map((_,i)=>  // set each value of the array at index i
    (i<n/2      // if we're on the left side,
    |n%2)       // or we're on the right and n is odd, even i => lower, odd i => higher
    ^i%2?       // else even i => higher, odd i => lower
    i+1:n-i
  )
N = <input type="number" id="input" oninput="result.textContent=solution(+this.value)" />
<pre id="result"></pre>


Bom algoritmo; Eu tentei e não consegui pensar em uma fórmula para gerá-las, então tive que usar o método mais feio de empurrar e desviar. No entanto, é claro que posso simplificar sua lógica para (i<n/2||n%2)^i%2?i+1:n-i.
214 Neil

@ Neil Wow, eu acabei de acordar, decidi jogar isso e surgiu com sua lógica exata e comecei a digitar da maneira que você postou! Louco ...
user81655

5

Python2, 105 98 bytes

7 bytes salvos graças ao comentário de @Dennis

n=input()
r=([],[n/2+1])[n%2]
for i in range(n/2,0,-1):k=[n+1-i];r=([i]+r+k,k+r+[i])[i%2]
print r

Versão editada 58 bytes

lambda n:[(n-i-1,i)[(i+(n,1)[i<n/2])%2]for i in range(n)]

Eu já acreditava que deveria ser possível fazê-lo como uma linha, mas a lógica era muito complexa para mim. Vendo a resposta JavaScript de @ user81655 e a notação lambda em @Dennis Python-answer, tentei novamente.

A condição é igual a

if i < n/2:
    i%2 != n%2
else:
    (i+1)%2

Infelizmente, todo o esforço de transformação economiza apenas um byte em comparação com a tradução direta (i<n/2or n%2)!=i%2da lógica JavaScript.


3
Bem-vindo à programação de quebra-cabeças e código de golfe! Parece ser o Python 2, então você não precisa int()da entrada. Além disso, você pode colocar o corpo do loop for na mesma linha que for....
Dennis

4

Python, 51 49 bytes

lambda n:[(i^min(i,~i%n)%-2)%n for i in range(n)]

Graças a @xnor por jogar fora 2 bytes!

Experimente em Ideone .

Como funciona

Se i é um número em [0, ..., n - 1] , então ~ i% n = - (i + 1)% n = - (i + 1) + n = (n - 1) - i , significando que mapeia 0 para n - 1 , 1 para n - 2 e, em geral, o j- ésimo item da esquerda para o j- ésimo da direita.

Como explicado na minha resposta Jelly , podemos construir a saída por espreitar pelo menor valor entre i e ~ i% n , e escolher i se é mesmo e ~ i% n se é estranho. Conseguimos isso da seguinte maneira.

  • Se o mínimo for par, min(i,~i%n)%-2produzirá 0 , então XORing o resultado com i produzirá i , e computando seu módulo de resíduo n retornará i .

  • Se o mínimo for ímpar, min(i,~i%n)%-2produzirá -1 , então XORing o resultado com i produzirá ~ i , para que toda a expressão seja avaliada como ~ i% n, conforme desejado.


Você pode salvar alguns caracteres fazendo o condicional como (i^min(i,n+~i)%-2)%n.
Xnor

Isso não é apenas curto, mas insanamente inteligente. Obrigado!
Dennis

2

PHP, 77 76 51 50 49 bytes

Usa codificação ISO 8859-1.

Montando a primeira metade da matriz assim:

  • Os números ímpares têm seu valor de índice (1, 3, 5 ..)
  • Números pares têm o valor de N+1-index(9, 7, 5)
  • Isto resulta em 1, 9, 3, 7, 5

Quanto à segunda metade da matriz, os valores mais externos são somados N+1, o que significa que você pode obter o valor correto correspondente de N-[left value]onde o valor esquerdo já é conhecido.

for(;$k=$argv[1]-$j++;)echo" ",min($j,$k)%2?$j:$k;

Execute assim (isso também mostra a diferença quadrática total) ( -dadicionado apenas para estética):

php -d error_reporting=32757 -r 'for(;$k=$argv[1]-$j++;)echo~ß,$x[]=min($j,$k)%2?$j:$k;  for(;$c=$x[+$i++];)$b+=($c-($x[$i]?:$x[0]))**2;echo"\n$b\n";' 10
  • Salva um byte negando a condição esquerda / direita para que o segundo ternário possa ser aninhado sem parênteses
  • Economizou 25 bytes implementando descaradamente o algoritmo de Dennis
  • Economizou um byte ao se livrar do espaço necessário após echo
  • Salva um byte usando para gerar um espaço.

1

Python 2, 100

Eu sei que já existe uma resposta em python, mas acho que posso ter feito isso de maneira diferente.

n=input();a=n%2;b=n/2;x=[b+1,b+a][a:]
for i in range(b+a-1):f=1-i%2*2;x=[x[-1]-f]+x+[x[0]+f]
print x

E como um extra para testar a pontuação total:

def t(x,n):return sum((x[i]-x[(i+1)%n])**2for i in range(n))

def t(x,n):return sum((x[i]-x[i-1])**2for i in range(n))usa o contorno implícito de índices negativos e salva 4 bytes. Eu sei, não fazia parte da competição. ;)
btwlf

1

CJam, 17 15 14 bytes

{,W%ee_::e<.=}

Esta é uma função que exibe um número inteiro n da pilha e empurra uma permutação de [0… n-1] em troca. O código usa a mesma abordagem da minha resposta Jelly .

Experimente online!

Como funciona

,W%ee_::e<.=    Function body. Stack: N

,               Turn N into [0 ... N-1].
 W%             Reverse to push [N-1 ... 0].
   ee           Enumerate. This pushes [[0 N-1] [1 N-2] ... [N-2 1] [N-1 0]].
     _          Push a copy of the array of pairs.
      ::e<      Reduce each pair by minimum.
          .=    Vectorized selection.
                For the Ith minimum M, select the Mth element of the Ith pair.
                Indices are modular and 0-based in CJam, so this selects the first
                element if the minimum is even, and the second one if it is odd.

1

LISP, 86 bytes

(defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

As entradas da função permitem escolher os valores inicial (m) e final (n) da sequência.

Para testar a função de acordo com as amostras fornecidas, n é fixado em N e m em 1.

Aqui o código para testar a função:

    (defun g(n m)(if(= n m)(list n)(if(< m n)(cons m(reverse(cons n(g(- n 1)(+ m 1))))))))

(defun sq (c)
    (apply #'+ (mapcar #'(lambda(x y) (* (- x y) (- x y))) c (append (cdr c) (list (car c))))))

(format t "N~20TSequence~50TSquared Difference~%")
(mapcar #'(lambda (x)(format t "~S~20T~S~50T~S~%" x (g x 1) (sq (g x 1)))) '(1 2 3 4 5 6 7 8 9 10 33 100 333 1000))

Experimente no Ideone !


1

Julia, 39 bytes

n->map(i->min(i-1,n-i)%2>0?n-~-i:i,1:n)

Isso imprime uma permutação de 1: n . Uma permutação de 0: n-1 não custa nem salva bytes:

n->map(i->min(i,n+~i)%2>0?i:n+~i,0:n-1)

Esta última versão é uma porta direta da minha resposta Python .


0

ES6, 77 bytes

n=>[...Array(n)].map(_=>r[++i&2?"push":"unshift"](i&1?n--:++j),i=j=0,r=[])&&r

As i&1amostras são os dígitos dos extremos para o meio. O i&2adiciona ao início ou ao final do resultado em pares.


0

R, 117 86 bytes

z=1:(n<-scan());a=pmin(z,n:1);for(i in seq(2,,2,n%/%2))z[b]=z[rev(b<-which(a==i,T))];z

editar versão longa com bugs substituída por uma implementação do algoritmo @Dennis 'Jelly

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.