Permutazioni sotto mentite spoglie


17

Dato un n vettore -dimensionale v con ingressi reali, per una permutazione vicini p di (1,2,...,n) rispetto alla l1 -distance.

Dettagli

  • Se è più conveniente, è possibile utilizzare permutazioni di (0,1,...,n1) , invece. Se sono presenti più permutazioni più vicine, è possibile emetterne una o in alternativa tutte.
  • L' l1 distanza tra due vettori u,v è definito come
    d(u,v)=i|uivi|.
  • Se lo desideri, puoi presumere che l'input sia costituito esclusivamente da numeri interi.

Esempi

[0.5  1] -> [1 2], [2 1]
c*[1 1 ... 1] -> any permutation
[1 4 2 6 2] -> [1 4 3 5 2], [1 4 2 5 3]
[1 3 5 4 1] -> [2 3 5 4 1], [1 3 5 4 2]
[7 7 3 2 5 6 4 2] -> [8 7 3 2 5 6 4 1], [8 7 3 1 5 6 4 2], [7 8 3 2 5 6 4 1], [7 8 3 1 5 6 4 2]
[-2 4 5 7 -1 9 3] -> [1 4 5 6 2 7 3], [2 4 5 6 1 7 3], [1 4 5 7 2 6 3], [2 4 5 7 1 6 3]
[0 4 2 10 -1 10 5] -> [1 4 2 6 3 7 5], [1 4 3 6 2 7 5], [2 4 3 6 1 7 5], [3 4 2 6 1 7 5], [1 4 2 7 3 6 5], [1 4 3 7 2 6 5], [2 4 3 7 1 6 5], [3 4 2 7 1 6 5]

Script di ottava per generare più esempi.


Siamo garantiti che tutti gli elementi di vsaranno maggiori di 0? O almeno no 0?
Shaggy,

1
No, le voci di vpossono essere numeri interi. (Aggiunti altri esempi.)
flawr

Se possono essere numeri reali, allora [1.6 2] è un caso di test importante (algoritmo avido / ordinamento lessicografico dà la risposta sbagliata).
histocrat,

2
Duplicato sotto mentite spoglie? Non sono sicuro che dovrebbe essere chiuso come tale, però, perché non è ovvio che sia lo stesso compito (come ora dimostrato da xnor).
Arnauld,

1
(In effetti, non è lo stesso compito, ma tutte le soluzioni della sfida collegata sono soluzioni di questo.)
Arnauld

Risposte:


13

Python 2 , 60 byte

def f(l):z=zip(l,range(len(l)));print map(sorted(z).index,z)

Provalo online!

Utilizza l'indicizzazione zero.

Un algoritmo veloce con un'idea semplice. Se invece necessario permutare lista di input per renderlo il più vicino a (1,2,...,n) come possibile, dovremmo appena sorta, come dimostrato qui sotto. Dal momento che stiamo invece permutando (1,2,...,n) , abbiamo scelto la permutazione di quel ordinato allo stesso modo come la lista di input, come nel mio sfida Imitare un ordinamento (tranne l'ingresso può avere ripetizioni). (Modifica: miglia ha sottolineato questa sfida più identica , in cui Dennis ha la stessa risposta .)

Modifica: Una permutazione dell'elenco l che minimizza la sua distanza (1,2,...,n) è l ordinati.

Prova: considera qualche altra permutazione l di l . Dimostreremo che non può essere migliore di quello che l ordinato.

Scegli due indici i,j che l ha fuori servizio, ecco dove i<j ma li>lj . Abbiamo dimostrato che scambiando loro non può aumentare la distanza (1,2,...,n) . Notiamo che lo swap modifica il contributo di questi due elementi come segue:

|lii|+|ljj||lij|+|lji|.

Ecco un modo accurato per dimostrare che questo non può essere un aumento. Consideriamo due persone che camminano su una linea numerica, una che va da li per i e l'altro da lj a j . La distanza totale che percorrono è l'espressione a sinistra. Poiché i<j ma li>lj , cambiano chi è più in alto sulla linea numerica, il che significa che devono attraversare ad un certo punto durante le loro passeggiate, chiamarlo p . Ma quando raggiungono p, potrebbero quindi scambiare le loro destinazioni e percorrere la stessa distanza totale. E poi, non può essere peggio per loro aver camminato verso le loro destinazioni scambiate dall'inizio piuttosto che usare p come waypoint, che fornisce la distanza totale sul lato destro.

Quindi, smistamento due elementi out-of-ordinare l rende la sua distanza (1,2,...,n) minore o uguale. Ripetendo questo processo alla fine l . Quindi, l ordinato è almeno buono quanto l per qualsiasi scelta di l , il che significa che è ottimale o legato per ottimale.

Si noti che l'unica proprietà di (1,2,...,n) che abbiamo usato è che è ordinato, in modo dallo stesso algoritmo funzionerebbe per permutare qualsiasi elenco di ridurre al minimo la sua distanza ad alcuna lista fisso.

Nel codice, l'unico scopo di z=zip(l,range(len(l)))è distinguere gli elementi di input, ovvero evitare legami, mantenendo gli stessi confronti tra elementi disuguali. Se l'input garantito non avesse ripetizioni, potremmo rimuoverlo e semplicemente lambda l:map(sorted(l).index,l).


brillante intuizione
Giona

Hai semplificato questo nel trovare l' ordinamento .
miglia

@miles That's pretty funny, I completely forgot about that challenge even though I wrote an answer, and Dennis has this exact Python answer which I helped golf.
xnor

That "visual proof" is neat. I got the same idea but had to lay out each case of that formula to prove it. As a side remark, a few alternatives of obtaining ranks in Python using third-party libraries are shown in this post.
Joel

5

05AB1E, 7 bytes

āœΣαO}н

Try it online!


Explanation

ā              # get the numbers 1 to len(input) + 1
 œ             # Permutations of this
  Σ  }         # Sort by ...
   α           # Absolute difference
    O          # Sum these
      н        # And get the first one 
               # implicitly print

1
Everytime i'm amazed by this, what 05AB1E can't do ?
The random guy

5
@Therandomguy Non ci sono molte cose che non si possono fare in 05AB1E, ma è piuttosto brutto in: sfide basate su regex; sfide basate sulla matrice (sebbene questo sia stato migliorato dopo alcuni nuovi builtin); mancanza di numeri immaginari; sfide relative a data / ora; ecc. Tuttavia, sebbene difficile, può ancora essere fatto di solito. Per fare due esempi: il conto alla rovescia del giorno lavorativo (vai al giorno successivo e ottieni il giorno della settimana sono fatti manualmente); Chine output stesso in binario (la conversione UTF-8 viene eseguita manualmente).
Kevin Cruijssen,

@Grimy dovrebbe essere risolto ora :)
Dati scaduti

3

Perl 6 , 44 byte

{permutations(+$_).min((*[]Z-$_)>>.abs.sum)}

Provalo online!

Blocco codice anonimo che restituisce la prima permutazione minima con 0 indicizzazione.

Spiegazione:

{                                          }   # Anonymous code block
 permutations(+$_)                             # From the permutations with the same length
                  .min(                   )    # Find the minimum by
                                      .sum       # The sum of
                                >>.abs           # The absolute values of
                       (*[]Z-$_)                 # The zip subtraction with the input

Penso che potrei anche essere in grado di sbarazzarmi di .sume ordinare solo dall'elenco dei valori assoluti, ma non sono sicuro che questo sia effettivamente corretto, anche se supera i miei attuali casi di test.


1
Anche quello mi stava spezzando il cervello (o la domanda per lo più equivalente di "funziona un algoritmo avido per questo?"). Il controesempio più semplice è [0.6 1](supponendo che siamo 0-indicizzati), dove se si ottimizza per il primo valore si ottiene [1,0]un punteggio di 1,4, ma se si ottimizza per l'intero vettore, l'1 è più prezioso nella seconda posizione per un punteggio di 0.6.
istocrato,


2

Jelly, 5 bytes

Œ¿œ?J

A monadic Link accepting a list of numbers which yields a list of integers.

Provalo online! Oppure vedi la suite di test .

Come?

Œ¿œ?J - Link: list of numbers, X
Œ¿    - Index of X in a lexicographically sorted list of
         all permutations of X's items
    J - range of length of X
  œ?  - Permutation at the index given on the left of the
         items given on the right

NB L(lunghezza) avrebbe funzionato al posto di Jdal œ?dato un intero, na destra avrebbe implicitamente rendere la gamma [1..n]con cui lavorare, ma Jè esplicito.


2

Rubino , 63 60 byte

->v{[*1..v.size].permutation.max_by{|p|eval [p,0]*'*%p+'%v}}

Provalo online!

C'è un trucco matematico che potrebbe essere utile anche in altre risposte - invece di ridurre al minimo la somma dei valori assoluti delle differenze, massimizziamo la somma dei prodotti. Perché funziona?

Ridurre al minimo la somma di (x-y) squarednon equivale a minimizzare la somma di |x-y|, ma fornirà sempre una risposta valida, dà semplicemente la priorità alla riduzione di grandi differenze rispetto a quelle piccole mentre la sfida effettiva è indifferente tra i due.

Ma (x-y)*(x-y)= x*x+y*y-2*x*y. Poiché i termini quadrati verranno sempre visualizzati da qualche parte nella somma per qualsiasi permutazione, non influenzano il risultato, quindi possiamo semplificare -2*x*y. I 2fattori fuori, così possiamo semplificare -x*y. Quindi se cambiamo minimizzando in massimizzando, possiamo semplificare x*y.

Intuitivamente, è simile all'osservazione che se stai cercando di massimizzare il metraggio quadrato usando una serie di pareti orizzontali e una serie di pareti verticali, è meglio abbinare pareti di dimensioni vicine tra loro per creare stanze che siano il più vicino possibile al quadrato. 3*3 + 4*4 = 25, mentre3*4 + 4*3 = 24 .

Modifica: salvato tre byte generando e valutando una stringa di formato anziché utilizzare zip e sum.


2
Ridurre al minimo la somma di (xy) al quadrato non equivale a minimizzare la somma di | xy |, ma fornirà sempre una risposta valida. Perché è così? No?y che minimizza Σ|X-y| ma no Σ(X-y)2?
Gioele,

1

Gaia , 13 byte

e:l┅f⟪D†Σ⟫∫ₔ(

Provalo online!

e:		| eval and dup input
l┅f		| push permutations of [1..length(input)]
⟪   ⟫∫ₔ		| iterate over the permutations, sorting with minimum first
 D†Σ		| the sum of the absolute difference of the paired elements
       (	| and select the first (minimum)

1

JavaScript (ES6), 61 byte

Basato sull'intuizione di xnor .

a=>[...a].map(g=n=>g[n]=a.sort((a,b)=>a-b).indexOf(n,g[n])+1)

Provalo online!

Commentate

a =>                    // a[] = input array
  [...a]                // create a copy of a[] (unsorted)
  .map(g = n =>         // let g be in a object; for each value n in the copy of a[]:
    g[n] =              //   update g[n]:
      a.sort(           //     sort a[] ...
        (a, b) => a - b //       ... in ascending order
      ).indexOf(        //     and find the position
        n,              //       of n in this sorted array,
        g[n]            //       starting at g[n] (interpreted as 0 if undefined)
      ) + 1             //     add 1
  )                     // end of map()

JavaScript (ES6),  130  128 byte

Ci  deve essere  sicuramente è un modo più diretto ...

0-indicizzati.

a=>(m=g=(k,p=[])=>1/a[k]?(h=i=>i>k||g(k+1,b=[...p],b.splice(i,0,k),h(-~i)))``:p.map((v,i)=>k+=(v-=a[i])*v)|k>m||(R=p,m=k))(0)&&R

Provalo online! (con uscita 1 indicizzata)

Come?

La funzione di aiuto g calcola tutte le permutazioni di (0,...,n-1), where n is the implicit length of the input array a[].

For each permutation p, we compute:

k=n1+i=0n1(piai)2
The only reason for the leading n1 is that we re-use the internal counter of g to save a few bytes, but it has no impact on the final result.

We eventually return the permutation that leads to the smallest k.



1

Python 2, 149 126 112 bytes

-23 bytes thanks to Mr. Xcoder

-14 bytes thanks to xnor

from itertools import*
f=lambda a:min(permutations(range(len(a))),key=lambda x:sum(abs(a-b)for a,b in zip(x,a)))

Try it online!

Uses permutations of (0 ... n-1).


Puoi passare a Python 2, in modo da non averne functoolspiù bisogno .
Mr. Xcoder,

reducedi solito è eccessivo, soprattutto qui dove stai aggiungendo cose. Penso che tu possa semplicemente fare sum(abs(p-q)for p,q in zip(x,a)).
xnor

0

senza alcun pacchetto di permutazione

Python 3 , 238 byte

def p(a,r,l):
 if r==[]:l+=[a];return
 for i in range(len(r)):
  p(a+[r[i]],r[:i]+r[i+1:],l)
def m(l):
 s=(float("inf"),0);q=[];p([],list(range(len(l))),q)
 for t in q:D=sum(abs(e-f)for e,f in zip(l,t));s=(D,t)if D<s[0]else s
 return s[1]

Provalo online!



0

Japt -g , 12 byte

Êõ á ñÈíaU x

Provalo

Per 0 indicizzato, sostituisci invece i primi 2 byte con m,per mappare l'array ai suoi indici.

Êõ á ñÈíaU x     :Implicit input of array U
Ê                :Length
 õ               :Range [0,Ê]
   á             :Permutations
     ñÈ          :Sort by
       í U       :  Interleave with U
        a        :  Reduce each pair by absolute difference
           x     :  Reduce resulting array by addition
                 :Implicit output of first sub-array

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.