Frittelle


27

Nell'ordinamento dei pancake l'unica operazione consentita è di invertire gli elementi di alcuni prefissi della sequenza. Oppure, pensa a una pila di pancake: inseriamo una spatola da qualche parte nella pila e capovolgiamo tutte le frittelle sopra la spatola.

Ad esempio, la sequenza 6 5 4 1 2 3può essere ordinata capovolgendo prima i primi 6elementi (l'intera sequenza), ottenendo il risultato intermedio 3 2 1 4 5 6e quindi capovolgendo i primi 3elementi, arrivando a 1 2 3 4 5 6.

Poiché esiste una sola operazione, l'intero processo di ordinamento può essere descritto da una sequenza di numeri interi, in cui ogni numero intero è il numero di elementi / pancake da includere pr flip. Per l'esempio sopra, la sequenza di ordinamento sarebbe 6 3.

Un altro esempio: 4 2 3 1può essere ordinato con 4 2 3 2. Ecco i risultati intermedi:

         4 2 3 1
flip 4:  1 3 2 4
flip 2:  3 1 2 4
flip 3:  2 1 3 4
flip 2:  1 2 3 4

L'obiettivo:

Scrivi un programma che prende un elenco di numeri interi e stampa una sequenza di ordinamento pancake valida.

L'elenco da ordinare può essere un elenco separato da spazi da stdin o argomenti della riga di comando. Stampa l'elenco comunque è conveniente, purché sia ​​in qualche modo leggibile.

Questo è codegolf!

Modificare:

Come ho detto nei commenti, non è necessario ottimizzare l'output (trovare la sequenza più breve è NP-difficile ). Tuttavia , mi sono appena reso conto che una soluzione economica sarebbe quella di lanciare numeri casuali fino a ottenere il risultato desiderato (un [nuovo?] Tipo di bogosort). Nessuna delle risposte finora ha fatto questo, quindi ora dichiaro che il tuo algoritmo non dovrebbe fare affidamento su alcuna (pseudo-) casualità .

Mentre ti prendi tutti a calci, ecco una variante di bogopancakesort in Ruby 2.0 (60 caratteri), per strofinarla:

a=$*.map &:to_i
a=a[0,p(v=rand(a.size)+1)].reverse+a[v..-1]while a!=a.sort

1
Qualche sequenza valida o dovrebbe essere di lunghezza minima?
Peter Taylor,

Piccolo errore di battitura: il secondo esempio mostra 4 3 2 1invece di4 2 3 1
beary605

4
(La mia connessione a Internet si è interrotta mentre provavo a modificarla, quindi la pubblicavo di nuovo) @PeterTaylor Sono stato tentato di includere una sorta di ottimizzazione in questo, ma ho scelto di non farlo. Trovare la lunghezza della sequenza minima è in realtà NP-difficile , mentre l'algoritmo più semplice e diretto può trovare una soluzione che al massimo sarà lunga 2n. Non so davvero come giudicherei questo come una sfida al codice / cosa di output ottimale, e mi piace di più il semplice codegolf :)
daniero,

Mi chiedo se qualcuno pubblicherà la propria partecipazione a questa sfida .
grc,

La sequenza deve essere valori contigui? 2 7 5 è un input valido?

Risposte:


6

GolfScript, 34/21 caratteri

(Grazie @PeterTaylor per aver tagliato 4 caratteri)

~].{,,{1$=}$\}2*${.2$?.p)p.@\-+}/,

Test online

Una versione più corta di 21 caratteri funziona solo per elenchi con elementi unici

~].${.2$?.p)p.@\-+}/,

Test online

Entrambe le versioni producono soluzioni non ottimali.


Spiegazione per la soluzione più breve:

~]         # read input from stdin
.$         # produce a sorted copy from lowest to highest
{          # iterate over the sorted list
  .2$?     # grab the index of the element
  .p       # print the index
  )p       # increment and print the index
  .@\-+    # move the element to the front
}/
,          # leave the length of the list on the stack
           # this flips the reverse sorted list to become sorted

Questo utilizza un algoritmo diverso rispetto alla maggior parte degli altri pubblicati. Fondamentalmente prende l'elemento più piccolo dell'elenco e con due lanci lo sposta in primo piano, preservando l'ordine degli altri elementi.

Per spostare l'ennesimo elemento in primo piano:

1 2 3 4 5 6 7   # let's move the 3rd (0-based) element to the front
# flip the first 3 elements
3 2 1 4 5 6 7
# flip the first 3+1 elements
4 1 2 3 5 6 7

Ripete questa operazione per ciascun elemento in ordine e termina con un elenco ordinato inverso. Quindi capovolge l'intero elenco per lasciarlo completamente ordinato.


In effetti l'algoritmo è una variante di una soluzione Python a 90 caratteri (la mia, ovviamente):

d=map(int,raw_input().split());i=0
while d:n=d.index(max(d));d.pop(n);print n+i,n-~i,;i+=1

2
Vedo che non hai riscontrato una delle stranezze di GolfScript: puoi usare qualsiasi token come variabile. Non stai usando da &nessuna parte, quindi dovresti essere in grado di sostituire swhile &e rimuovere gli spazi bianchi.
Peter Taylor,

@PeterTaylor huh, mi chiedevo perché potresti usare ^come variabile nella sfida fibonacci;) Grazie per il suggerimento!
Volatilità

Per l'input 3 2 1ottengo 131211che non è corretto.
Howard,

@Howard ha funzionato ora
Volatilità

@Volatility L'ultima modifica è stata un po 'troppo ;-) Ad esempio le liste come 2 1 1non possono più essere ordinate.
Howard,

11

Python, 91 90 caratteri

L=map(int,raw_input().split())
while L:i=L.index(max(L));print-~i,len(L),;L=L[:i:-1]+L[:i]

Capovolgi il pancake più grande verso l'alto, quindi capovolgi l'intero stack. Rimuovi il pancake più grande dal basso e ripeti.

iè l'indice del pancake più grande. L=L[:i:-1]+L[:i]lancia i i+1pancake, lancia i len(L)pancake, quindi rilascia l'ultimo pancake.


1
Pensavo che ti fosse permesso di fare solo capriole. (Cioè, non pensavo che potresti far cadere i pancake dallo stack). Ho frainteso le regole? Hmm. va di nuovo a leggere la pagina wiki Indipendentemente da ciò, bel lavoro :) Meno di 100 caratteri è abbastanza sorprendente per me!
WendiKidd,

@WendiKidd In realtà, ciò che significa è che dopo aver capovolto il più grande, lo sta semplicemente ignorando e si preoccupa con i pancake sopra.
AJMansfield,

@AJMansfield Ah, capisco! Grazie, ha senso. Non riesco a leggere il codice (sono troppo nuovo per Python) quindi ho frainteso la spiegazione :) Grazie!
WendiKidd,

2
Praticamente un'evoluzione di ciò che ho scritto prima. Non pensavo di rimuovere gli elementi perché all'inizio dovevo verificare la correttezza dell'output (cioè l'elenco viene ordinato in seguito?). A proposito: credo che la rimozione della virgola da printnon renda l'output illeggibile (1 byte salvato :)
Bakuriu,

@WendiKidd in realtà, a un'ulteriore ispezione, rimuove effettivamente i pancake; deve solo capire qual è la sequenza di lanci, non effettivamente ordinare l'array.
AJMansfield,

6

Rubino 1.9 - 109 88 79 caratteri

Versione molto più compatta basata sull'ottima soluzione Python di Keith:

a=$*.map &:to_i;$*.map{p v=a.index(a.max)+1,a.size;a=a[v..-1].reverse+a[0,v-1]}

Versione originale:

a=$*.map &:to_i
a.size.downto(2){|l|[n=a.index(a[0,l].max)+1,l].map{|v|v>1&&n<l&&p(v);a[0,v]=a[0,v].reverse}}

Se non ti interessano le operazioni spurie (invertire pile di dimensione 1 o invertire lo stesso mazzo due volte di seguito) puoi renderlo un po 'più corto (96 caratteri):

a=$*.map &:to_i
a.size.downto(2){|l|[a.index(a[0,l].max)+1,l].map{|v|p v;a[0,v]=a[0,v].reverse}}

Accetta l'elenco non ordinato come argomenti della riga di comando. Esempio di utilizzo:

>pc.rb 4 2 3 1
4
2
3
2

6

GolfScript, 31 29 caratteri

~].${1$?).p.2$.,p>-1%\@<+)}%,

Un'altra soluzione GolfScript, può anche essere testata online .

Versione precedente:

~].$-1%{1$?).2$>-1%@2$<+.,\);}/

Come funziona: capovolge l'elemento più grande in alto e poi all'ultimo posto nell'elenco. Poiché ora è nella posizione corretta, possiamo rimuoverlo dall'elenco.

~]         # Convert STDIN (space separated numbers) to array
.$-1%      # Make a sorted copy (largest to smallest)
{          # Iterate over this copy
  1$?)     # Get index of item (i.e. largest item) in the remaining list,
           # due to ) the index starts with one
  .        # copy (i.e. index stays there for output)
  2$>      # take the rest of the list...
  -1%      # ... and reverse it 
  @2$<     # then take the beginning of the list
  +        # and join both. 
           # Note: these operations do both flips together, i.e.
           # flip the largest item to front and then reverse the complete stack
  .,       # Take the length of the list for output
  \);      # Remove last item from list
}/

4

Perl, 103 100 caratteri

Si aspetta input dalla riga di comando.

for(@n=sort{$ARGV[$a]<=>$ARGV[$b]}0..$#ARGV;@n;say$i+1,$/,@n+1)
{$i=pop@n;$_=@n-$_-($_<=$i&&$i)for@n}

Le soluzioni che stampa sono decisamente non ottimali. (Avevo un programma con un output molto più bello circa 24 caratteri fa ....)

La logica è piuttosto interessante. Inizia catalogando l'indice di ogni articolo, se fosse in ordine. Quindi scorre attraverso questo catalogo da destra a sinistra. Quindi l'applicazione di un capovolgimento implica la regolazione degli indici al di sotto del valore di cutoff, invece di spostare effettivamente i valori. Dopo un po 'di finagling sono anche riuscito a salvare alcuni personaggi eseguendo entrambi i lanci per iterazione contemporaneamente.


3

Python 2 (254)

Semplice ricerca BFS, alcune cose sono inline, probabilmente potrebbero essere più compresse senza cambiare lo stile di ricerca. Spero che questo mostri forse come iniziare a giocare a golf un po '(troppo per essere in un semplice commento).

Uso:

python script.py 4 2 3 1

(2 spazi = tab)

import sys
t=tuple
i=t(map(int,sys.argv[1:]))
g=t(range(1,len(i)+1))
q=[i]
p={}
l={}
while q:
 c=q.pop(0)
 for m in g:
  n=c[:m][::-1]+c[m:]
  if n==g:
   s=[m]
   while c!=i:s+=[l[c]];c=p[c]
   print s[::-1]
   sys.exit()
  elif n not in p:q+=[n];p[n]=c;l[n]=m

1
Puoi sostituirlo sys.exit()con 1/0(in codegolf non ti importa mai di ciò che viene stampato in stderr ...).
Bakuriu,

Certo, potrei fare print s[::-1];1/0per radere alcuni caratteri.
miglia

Il BFS è molto interessante, ma eseguirlo con 4 2 3 12 3 2 4, che in realtà non è valido.
daniero,

1
@daniero In che modo tale output non è valido? 4 2 3 1-> 2 4 3 1-> 3 4 2 1-> 4 3 2 1->1 2 3 4
Gareth,

@Gareth non ne ho idea! E l'ho anche controllato due volte .. Oh bene, allora non importa :) Bella soluzione, miglia t.
daniero,

3

Python2: 120

L=map(int,raw_input().split())
u=len(L)
while u:i=L.index(max(L[:u]))+1;L[:i]=L[i-1::-1];L[:u]=L[u-1::-1];print i,u;u-=1

Non è efficiente: non troverà la migliore sequenza di ordinamento e la sequenza data può anche contenere nessuna operazione (ovvero lanciando solo il primo elemento), tuttavia l'output è valido.

L'output viene fornito nel formato:

n_1 n_2
n_3 n_4
n_5 n_6
...

Che va letto come la sequenza di lanci: n_1 n_2 n_3 n_4 n_5 n_6 .... Se si desidera ottenere un output come:

n_1 n_2 n_3 n_4 n_5 n_6 ...

Aggiungi semplicemente una virgola printnell'istruzione.


[:i][::-1]-> [i-1::-1], [:u][::-1]-> [u-1::-1], salva 2 caratteri
Volatilità

In effetti, L[:i]=L[i-1::-1];L[:u]=[u-1::-1]salva altri 3 caratteri
Volatilità l'

@Volatilità Grazie per i suggerimenti. Incluso.
Bakuriu,

3

Python - 282 caratteri

import sys
s=sys.argv[1]
l=s.split()
p=[]
for c in l:
 p.append(int(c))
m=sys.maxint
n=0
while(n==(len(p)-1)):
 i=x=g=0
 for c in p:
  if c>g and c<m:
   g=c
   x=i
  i+=1
 m=g
 x+=1
 t=p[:x]
 b=p[x:]
 t=t[::-1]
 p=t+b
 a=len(p)-n;
 t=p[:a]
 b=p[a:]
 t=t[::-1]
 p=t+b
 print p
 n+=1

Il mio primo codice golf in assoluto; Sono illusioni io vinco , ma ho avuto un sacco di divertimento. Dare a tutti i nomi di un personaggio sicuramente rende spaventoso leggere, lascia che te lo dica! Viene eseguito dalla riga di comando, esempio di implementazione di seguito:

Python PancakeSort.py "4 2 3 1"
[1, 3, 2, 4]
[2, 1, 3, 4]
[1, 2, 3, 4]

Non c'è niente di particolarmente speciale o inventivo nel modo in cui sono andato su questo, ma le FAQ suggeriscono di pubblicare una versione non golfata per i lettori interessati, quindi l'ho fatto di seguito:

import sys

pancakesStr = sys.argv[1]
pancakesSplit = pancakesStr.split()
pancakesAr = []
for pancake in pancakesSplit:
    pancakesAr.append(int(pancake))

smallestSorted = sys.maxint
numSorts = 0

while(numSorts < (len(pancakesAr) - 1)):
    i = 0
    biggestIndex = 0
    biggest = 0
    for pancake in pancakesAr:
        if ((pancake > biggest) and (pancake < smallestSorted)):
            biggest = pancake
            biggestIndex = i
        i += 1

    smallestSorted = biggest  #you've found the next biggest to sort; save it off.
    biggestIndex += 1   #we want the biggestIndex to be in the top list, so +1.

    top = pancakesAr[:biggestIndex]
    bottom = pancakesAr[biggestIndex:]

    top = top[::-1] #reverse top to move highest unsorted number to first position (flip 1)
    pancakesAr = top + bottom   #reconstruct stack

    alreadySortedIndex = len(pancakesAr) - numSorts;

    top = pancakesAr[:alreadySortedIndex]
    bottom = pancakesAr[alreadySortedIndex:]

    top = top[::-1] #reverse new top to move highest unsorted number to the bottom position on the unsorted list (flip 2)
    pancakesAr = top + bottom   #reconstruct list

    print pancakesAr    #print after each flip

    numSorts += 1

print "Sort completed in " + str(numSorts) + " flips. Final stack: "
print pancakesAr

L'algoritmo di base che ho usato è quello menzionato nell'articolo wiki collegato alla domanda :

L'algoritmo di ordinamento del pancake più semplice richiede al massimo 2n-3 lanci. In questo algoritmo, una variazione dell'ordinamento di selezione, portiamo il pancake più grande non ancora ordinato in alto con un capovolgimento, quindi lo portiamo nella sua posizione finale con un altro, quindi ripetiamo questo per i pancake rimanenti.


1
Alcuni consigli per giocare a golf: quattro spazi per il rientro sono dispendiosi. Meglio: usare uno spazio; ancora meglio: combina schede e spazi per ridurre ancora di più.
John Dvorak,

1
t=p[:x] t=t[::-1](16 + rientro) può essere ridotto a t=p[:x][::-1](13) o anche t=p[x-1::-1](12). Inline tutto il possibile:p=p[x-1::-1]+p[x:]
John Dvorak l'

Usa gli indici negativi per contare dal retro. len(a)-ndiventa -n; p=p[-n-1::-1]+p[-n:]. Ulteriore golf utilizzando le giuste operazioni:p=p[~n::-1]+p[-n:]
John Dvorak,

1
Umm ... dovresti stampare l'intera sequenza di lanci, non solo il risultato finale.
John Dvorak,

Cosa ha detto Jan Dvorak. Benvenuto a codegolf a proposito. Puoi facilmente tagliare il conteggio dei personaggi a metà con alcune semplici misure; alcuni sono stati menzionati. Inoltre, le variabili intermedie non vanno bene. La comprensione dell'elenco è buona. Ma se stai usando sys.argv puoi anche lasciare che ogni numero dell'input sia un argomento, quindi map(int,sys.argv[1:])fa quello che fanno le tue 6 prime righe adesso. i=x=g=0funziona, ma dovresti comunque tagliare la quantità di variabili. Ti do una cosa però: questa è l'unica voce di pitone di cui ho capito il minimo: D
daniero,

3

C # - 264 259 252 237 caratteri

Utilizza l'algoritmo più semplice e produce un output corretto senza ribaltamenti ridondanti. Potrei radere 7 caratteri se gli consentissi di includere 1 (non-flip) nell'output, ma è brutto.

Ho fatto ricorso all'uso gotoper il massimo golfage. Inoltre ha salvato alcuni caratteri consentendogli di eseguire non-flip (ma non stamparli).

Ultimo miglioramento: mantenere l'input array come stringhe invece di convertirlo in ints.

using System.Linq;class P{static void Main(string[]a){var n=a.ToList();for(int p
=n.Count;p>0;p--){int i=n.IndexOf(p+"")+1;if(i<p){f:if(i>1)System.Console.Write
(i);n=n.Take(i).Reverse().Concat(n.Skip(i)).ToList();if(i!=p){i=p;goto f;}}}}}

Ungolfed:

using System.Linq;
class Program
{
    static void Main(string[] args)
    {
        var numbers = args.ToList();

        for (int pancake = numbers.Count; pancake > 0; pancake--)
        {
            int index = numbers.IndexOf(pancake+"") + 1;
            if (index < pancake)
            {
                flip:

                if (index > 1)
                    System.Console.Write(index);

                numbers = numbers.Take(index)
                                 .Reverse()
                                 .Concat(numbers.Skip(index))
                                 .ToList();

                if (index != pancake)
                {
                    index = pancake;
                    goto flip;
                }
            }
        }
    }
}

Ecco la mia soluzione iniziale, non golfata (264 caratteri giocati a golf):

using System.Linq;
using System;

class Program
{
    static void Main(string[] args)
    {
        var numbers = args.Select(int.Parse).ToList();

        Action<int> Flip = howMany =>
        {
            Console.Write(howMany);
            numbers = numbers.Take(howMany)
                             .Reverse()
                             .Concat(numbers.Skip(howMany))
                             .ToList();
        };

        for (int pancake = numbers.Count; pancake > 0; pancake--)
        {
            int index = numbers.IndexOf(pancake) + 1;
            if (index < pancake)
            {
                if (index > 1)
                    Flip(index);
                Flip(pancake);
            }
        }
    }
}

Non gestisce sequenze non contigue, fornendo risultati errati con tali input.

@hatchet: non sono sicuro di cosa intendi. Puoi farmi un esempio?
Igby Largeman,

Dato un input di 1 22, il risultato dice di fare uno scambio, il che porterebbe a 22 1. Penso che il tuo codice si aspetti che la sequenza includa numeri contigui (es: 2 4 1 3), ma non prevede input come ( 2 24 5 5 990).

@hatchet: In effetti, non ho fatto alcun tentativo di supportare le lacune nella sequenza, perché non avrebbe senso. L'idea del pancake sort è di ordinare una pila di oggetti, non un gruppo di numeri arbitrari. Il numero associato a ciascun oggetto identifica la sua posizione corretta nello stack. Pertanto i numeri inizieranno sempre con 1 e saranno contigui.
Igby Largeman,

Non ero sicuro, perché la domanda diceva "sequenza", e in matematica {1, 22} è una sequenza valida, ma entrambi gli esempi erano numeri contigui. Quindi ho chiesto chiarimenti al PO (vedi commenti sulla domanda). Penso che la maggior parte delle risposte qui gestirà le lacune, ok.

2

Haskell , 72 71 byte

h s|(a,x:b)<-span(<maximum s)s=map length[x:a,s]++h(reverse b++a)
h e=e

Provalo online! Trova il massimo, lo ribalta sul retro e ordina ricorsivamente l'elenco rimanente.

Modifica: -1 byte grazie a BMO


2

Perl 5,10 (o superiore), 66 byte

Include +3for -n The use 5.10.0per portare la lingua al livello perl 5.10 è considerato gratuito

#!/usr/bin/perl -n
use 5.10.0;
$'>=$&or$.=s/(\S+) \G(\S+)/$2 $1/*say"$. 2 $."while$.++,/\S+ /g

Esegui con l'input come una riga su STDIN:

flop.pl <<< "1 8 3 -5 6"

Ordina l'elenco trovando ripetutamente qualsiasi inversione, capovolgendola in avanti, quindi capovolgendo l'inversione e riportando tutto alla sua vecchia posizione. E questo equivale a scambiare l'inversione, quindi non ho bisogno di invertire (il che è scomodo sulle stringhe poiché rovescerebbe le cifre dei valori convertendo ad esempio 12in 21)


1

C # - 229

using System;using System.Linq;class P{static void Main(string[] a){
var n=a.ToList();Action<int>d=z=>{Console.Write(z+" ");n.Reverse(0,z);};
int c=n.Count;foreach(var s in n.OrderBy(x=>0-int.Parse(x))){
d(n.IndexOf(s)+1);d(c--);}}}

versione leggibile

using System;
using System.Linq;
class P {
    static void Main(string[] a) {
        var n = a.ToList();
        Action<int> d = z => { Console.Write(z + " "); n.Reverse(0, z); };
        int c = n.Count;
        foreach (var s in n.OrderBy(x => 0 - int.Parse(x))) {
            d(n.IndexOf(s) + 1); d(c--);
        }
    }
}
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.