Massimizza la differenza quadrata


19

Considera una permutazione dei valori interi da 1a N. Ad esempio questo esempio per N = 4:

[1, 3, 4, 2]

Noi considereremo questo elenco per essere ciclico, in modo tale che 1e 2sono trattati come adiacente. Una quantità che possiamo calcolare per tale elenco è la differenza quadrata totale dei valori adiacenti:

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

Il tuo compito è trovare una permutazione che massimizzi questa quantità, dato un numero intero positivo N. Nel caso dell'esempio N = 4precedente non è ottimale (in realtà, è minimo). Possiamo ottenere una differenza al quadrato totale 18con la seguente permutazione (così come molte altre):

[1, 4, 2, 3]

L'algoritmo deve essere eseguito in un tempo polinomiale (di N). In particolare, non puoi semplicemente calcolare la differenza quadrata totale di tutte le permutazioni.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN (o l'alternativa più vicina), l'argomento della riga di comando o l'argomento della funzione e producendo il risultato tramite STDOUT (o l'alternativa più vicina), il valore di ritorno della funzione o il parametro della funzione (out).

L'output può essere in qualsiasi elenco o formato stringa conveniente, inequivocabile. È possibile scegliere di restituire un elenco con valori da 0a N-1anziché 1a N.

Si applicano le regole standard del .

Dati di test

Esiste una buona soluzione analitica per questo problema. Ad esempio, tutte le soluzioni valide N = 10sono equivalenti al seguente elenco (fino a turni e inversioni cicliche):

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

Non voglio rivelare troppo oltre (anche se probabilmente è abbastanza per capire il modello), quindi invece di dare altri esempi, puoi verificare che i tuoi risultati abbiano le seguenti differenze al quadrato totali per un dato 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

Questa è la voce OEIS A064842 (che contiene anche un riferimento a un documento con una soluzione a questa sfida se sei bloccato).

Risposte:


7

Gelatina, 24 21 15 14 10 9 byte

RUĖµ«/€ị"

Per calcolare la differenza quadrata totale, aggiungi µ_ṙ1$²Sal codice. Provalo online!

sfondo

Un modo per generare una permutazione con differenza quadrata massimizzata è prendere gli interi da 1 a n in ordine crescente e scambiare il secondo da sinistra con il secondo da destra, il quarto da sinistra con il quarto da destra, e così avanti fino a quando ci incontriamo nel mezzo.

Ad esempio, per n = 8, 9 abbiamo

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

(i segni di inserimento contrassegnano i numeri interi da scambiare), che risulta in

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

dopo lo scambio.

Un modo per ottenere questi swap, indipendentemente dalla parità di n , è il seguente.

Inizia scrivendo i numeri interi in ordine crescente e in ordine decrescente, uno sotto l'altro.

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

Per ogni coppia di numeri interi, calcola il minimo della coppia. Ciò fornisce la distanza dal bordo più vicino, ovvero l'indice da sinistra o destra (qualunque sia il più basso).

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 il minimo è dispari, l'intero dovrebbe rimanere al suo posto, quindi selezioniamo quello dalla prima riga; se è pari, gli interi devono essere scambiati, quindi selezioniamo quello dalla seconda riga.

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

Questo è l'output desiderato.

Come funziona

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 byte

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

9 byte salvati grazie a @Neil!

Spiegazione

Questo approccio determina il numero che dovrebbe essere nell'indice icon una lunghezza nanziché concatenare i risultati in un array. Questo si basa sulla seguente osservazione (usando n = 7come esempio):

  • Inizia con il numero più basso a sinistra e il più alto a destra: [ 1, 7 ]
  • Cambia l'ordine in modo che il più basso sia a destra e il più alto sia a sinistra, incrementa il più basso, decrementa il più alto e posizionali al centro dell'array:[ 1, 6, 2, 7 ]
  • Ripeti fino a quando il massimo e il minimo convergono: [ 1, 6, 3, 4, 5, 2, 7 ]

I numeri più alti e più bassi possono essere facilmente espressi come n-ie i+1rispettivamente.

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>


Algoritmo piacevole; Ho provato e non sono riuscito a pensare a una formula per generarli, quindi ho dovuto usare il metodo più brutto di spingere e spostare. Tuttavia, posso ovviamente semplificare la tua logica (i<n/2||n%2)^i%2?i+1:n-i.
Neil,

@Neil Wow, mi sono appena svegliato, ho deciso di giocare a golf e ho trovato la tua logica esatta e ho iniziato a scriverlo nel modo giusto quando l'hai pubblicato! Crazy ...
user81655,

5

Python2, 105 98 byte

7 byte salvati grazie al commento di @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

Versione modificata 58 byte

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

Pensavo già che sarebbe stato possibile farlo come una linea, ma la logica era troppo complessa per me. Vedendo la risposta JavaScript di @ user81655 e la notazione lambda in @Dennis Python-answer, ho fatto un nuovo tentativo.

La condizione è uguale a

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

Sfortunatamente tutto lo sforzo di trasformazione fa risparmiare solo un byte no rispetto alla traduzione diretta (i<n/2or n%2)!=i%2della logica JavaScript.


3
Benvenuto in Programmazione di puzzle e codice golf! Questo sembra essere Python 2, quindi non hai bisogno int()dell'input intorno. Inoltre, puoi mettere il corpo del ciclo for sulla stessa linea di for....
Dennis,

4

Python, 51 49 byte

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

Grazie a @xnor per giocare a golf con 2 byte!

Provalo su Ideone .

Come funziona

Se i è un numero in [0, ..., n - 1] , quindi ~ i% n = - (i + 1)% n = - (i + 1) + n = (n - 1) - i , il che significa che le mappe 0 a n - 1 , 1 a n - 2 e, in generale, la j esimo elemento dalla sinistra alla j esimo da destra.

Come spiegato nella mia risposta Jelly , possiamo costruire l'output dando una sbirciatina al valore più basso tra i e ~ i% n , e scegliere i se è pari e ~ i% n se è dispari. Raggiungiamo questo come segue.

  • Se il minimo è pari, min(i,~i%n)%-2produrrà 0 , quindi XORing il risultato con i produrrà i e calcolando il suo modulo residuo n restituirà i .

  • Se il minimo è dispari, min(i,~i%n)%-2produrrà -1 , quindi XORing il risultato con i produrrà ~ i , quindi l'intera espressione viene valutata come ~ i% n come desiderato.


Puoi salvare un paio di caratteri eseguendo il condizionale come (i^min(i,n+~i)%-2)%n.
xnor

Non è solo breve ma follemente intelligente. Grazie!
Dennis,

2

PHP, 77 76 51 50 49 byte

Utilizza la codifica ISO 8859-1.

Assemblando la prima metà dell'array in questo modo:

  • I numeri dispari hanno il loro valore di indice (1, 3, 5 ..)
  • I numeri pari hanno il valore di N+1-index(9, 7, 5)
  • Questo risulta in 1, 9, 3, 7, 5

Come per la seconda metà dell'array, i valori più esterni si sommano a N+1, il che significa che è possibile ottenere il valore corretto corrispondente da N-[left value]cui è già noto il valore sinistro.

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

Esegui in questo modo (mostra anche la differenza quadratica totale) ( -daggiunto solo per l'estetica):

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
  • Salvataggio di un byte annullando la condizione sinistra / destra in modo che il secondo ternario possa essere nidificato senza parentesi
  • Hai salvato 25 byte implementando spudoratamente l'algoritmo di Dennis
  • Dopo aver salvato un byte, liberarsi dello spazio necessario echo
  • Hai salvato un byte usando per dare uno spazio.

1

Python 2, 100

So che esiste già una risposta Python, ma penso che avrei potuto farlo diversamente.

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 come extra per testare il punteggio totale:

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))utilizza il wrapping implicito di indici negativi e salva 4 byte. Lo so, non faceva parte della competizione. ;)
btwlf,

1

CJam, 17 15 14 byte

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

Questa è una funzione che estrae un numero intero n dallo stack e invia in cambio una permutazione di [0… n-1] . Il codice utilizza lo stesso approccio della mia risposta Jelly .

Provalo online!

Come funziona

,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 byte

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

Gli ingressi della funzione consentono di scegliere i valori di inizio (m) e fine (n) della sequenza.

Per testare la funzione secondo i campioni forniti, n è fisso su N e m su 1.

Ecco il codice per testare la funzione:

    (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))

Provalo su Ideone !


1

Julia, 39 byte

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

Questo stampa una permutazione di 1: n . Una permutazione di 0: n-1 non costa né salva byte:

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

Quest'ultima versione è una porta diretta della mia risposta Python .


0

ES6, 77 byte

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

I i&1campioni i numeri estremi verso il centro. Le i&2aggiunge all'inizio o alla fine del risultato in coppie.


0

R, 117 86 byte

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

modifica la versione lunga buggy sostituita con un'implementazione dell'algoritmo Jelly di @Dennis

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.