Come posso accoppiare i calzini da una pila in modo efficiente?


3912

Ieri stavo accoppiando i calzini dalla biancheria pulita e ho capito che il modo in cui lo stavo facendo non è molto efficiente. Stavo facendo una ricerca ingenua, raccogliendo un calzino e "ripetendo" la pila per trovare la sua coppia. Ciò richiede l'iterazione di n / 2 * n / 4 = n 2 /8 calzini in media.

Come informatico stavo pensando a cosa avrei potuto fare? L'ordinamento (in base alla dimensione / colore / ...) ovviamente mi è venuto in mente per ottenere una soluzione O (NlogN).

Hashing o altre soluzioni non sul posto non sono un'opzione, perché non sono in grado di duplicare i miei calzini (anche se potrebbe essere bello se potessi).

Quindi, la domanda è sostanzialmente:

Dato un mucchio di npaia di calze, contenente 2nelementi (supponiamo che ogni calza abbia esattamente una coppia corrispondente), qual è il modo migliore per accoppiarli in modo efficiente con spazio extra logaritmico? (Credo di poter ricordare quella quantità di informazioni se necessario.)

Apprezzerò una risposta che affronta i seguenti aspetti:

  • Una soluzione teorica generale per un numero enorme di calze.
  • Il numero effettivo di calze non è così grande, non credo al mio coniuge e ho più di 30 paia. (Ed è abbastanza facile distinguere tra i miei calzini e i suoi; può essere usato anche questo?)
  • È equivalente al problema della distinzione tra elementi ?

448
Uso il principio del foro per piccione per accoppiare esattamente uno dalla pila di biancheria. Ho 3 diversi colori di calze (rosso, blu e verde) e 2 paia di ogni colore. Raccolgo 4 numero di calze ogni volta e ne faccio sempre un paio e mi metto al lavoro.
Srinivas,

59
Ancora un altro principio del buco del piccione: se prendi un sottoinsieme di calze n / 2 +1, ci deve essere almeno una coppia in questo sottoinsieme.
wildplasser,

40
Ottima domanda! Potresti essere interessato al mio articolo su un problema correlato, che è una discussione sulla probabilità di estrarre dalla pila due calzini abbinati: blogs.msdn.com/b/ericlippert/archive/2010/03/22/…
Eric Lippert,

336
Perché non generare un bambino e in waitpidmodo che, come genitore, non stia nemmeno ordinando i calzini da soli?
Mxyk,

137
Ho risolto questo problema possedendo solo calze bianche alte fino al ginocchio. Tutti corrispondono. Potrei semplicemente prendere due calzini a caso dalla pila e si abbinerebbero. Semplifico ulteriormente il problema NON accoppiando le calze. Ho un cassetto per calzini in cui semplicemente lancio tutti i miei calzini, spaiato. Ne prendo due a caso dal cassetto ogni mattina. L'ho semplificato fino a O (0). Non c'è niente di più semplice di così. :)
Lee,

Risposte:


2450

Sono state proposte soluzioni di ordinamento, ma l' ordinamento è un po 'troppo : non abbiamo bisogno di ordine; abbiamo solo bisogno di gruppi di uguaglianza .

Quindi l' hashing sarebbe abbastanza (e più veloce).

  1. Per ogni colore di calze, forma una pila . Scorrere su tutte le calze nel cestino di input e distribuirle sulle pile di colori .
  2. Scorrere su ciascuna pila e distribuirla per qualche altra metrica (ad es. Modello) nella seconda serie di pile
  3. Applicare in modo ricorsivo questo schema fino a quando non sono state distribuite tutte le calze su pile molto piccole che è possibile elaborare visivamente immediatamente

Questo tipo di partizionamento hash ricorsivo viene effettivamente eseguito da SQL Server quando deve unire hash o aggregare hash su enormi set di dati. Distribuisce il flusso di input della build in molte partizioni indipendenti. Questo schema si ridimensiona in modo lineare a quantità arbitrarie di dati e più CPU.

Non è necessario il partizionamento ricorsivo se è possibile trovare una chiave di distribuzione (chiave hash) che fornisce abbastanza bucket da consentire a ciascun bucket di essere abbastanza piccolo da essere elaborato molto rapidamente. Sfortunatamente, non penso che i calzini abbiano una tale proprietà.

Se ogni calzino avesse un numero intero chiamato "PairID", si potrebbe facilmente distribuirli in 10 secchi secondo PairID % 10(l'ultima cifra).

Il miglior partizionamento del mondo reale a cui riesco a pensare è la creazione di un rettangolo di pile : una dimensione è il colore, l'altra è il modello. Perché un rettangolo? Perché abbiamo bisogno di O (1) accesso casuale alle pile. (Anche un cuboide 3D funzionerebbe, ma non è molto pratico.)


Aggiornare:

Che dire del parallelismo ? Possono più esseri umani abbinare le calze più velocemente?

  1. La strategia di parallelizzazione più semplice consiste nel fare in modo che più lavoratori prendano dal paniere di input e mettano i calzini sulle pile. Questo aumenta solo così tanto: immagina 100 persone che combattono su 10 pile. I costi di sincronizzazione (che si manifestano come collisioni manuali e comunicazioni umane) distruggono l'efficienza e l'accelerazione (vedi la Legge sulla scalabilità universale !). È soggetto a deadlock ? No, perché ogni lavoratore deve solo accedere a una pila alla volta. Con un solo "blocco" non può esserci un deadlock. Livelocks potrebbe essere possibile a seconda di come gli umani coordinano l'accesso alle pile. Potrebbero semplicemente usare il backoff casualecome le schede di rete lo fanno a livello fisico per determinare quale scheda può accedere esclusivamente al cavo di rete. Se funziona per le schede di rete , dovrebbe funzionare anche per gli esseri umani.
  2. Ridimensiona quasi indefinitamente se ogni lavoratore ha il proprio set di pile . I lavoratori possono quindi prendere grossi pezzi di calzini dal paniere di input (pochissima contesa in quanto lo fanno raramente) e non devono sincronizzarsi quando distribuiscono i calzini (perché hanno pile di thread locali). Alla fine, tutti i lavoratori devono unire le proprie pile. Credo che si possa fare in O (log (conteggio dei lavoratori * pile per lavoratore)) se i lavoratori formano un albero di aggregazione .

Che dire del problema di distinzione tra elementi ? Come afferma l'articolo, il problema di distinzione tra elementi può essere risolto O(N). Questo è lo stesso per il problema dei calzini (inoltre O(N), se hai bisogno di un solo passo di distribuzione (ho proposto più passaggi solo perché gli umani sono cattivi nei calcoli - un passo è sufficiente se li distribuisci md5(color, length, pattern, ...), cioè un hash perfetto di tutti gli attributi)).

Chiaramente, non si può andare più veloci di O(N), quindi abbiamo raggiunto il limite inferiore ottimale .

Sebbene le uscite non siano esattamente le stesse (in un caso, solo un booleano. Nell'altro caso, le coppie di calze), le complessità asintotiche sono le stesse.


72
Questo è esattamente quello che faccio! Rendo le pile dipendenti dallo stile dell'apertura della calza (ho solo bianco), che mi dà abbastanza "secchi" per abbinare rapidamente ognuno di quelli in alto.
Scott Chamberlain,

30
L'ho provato con i miei calzini (ho facilmente più di 30 paia) e amico è VELOCE. Un problema che ho riscontrato è quando non riesco ad avere un algoritmo hash abbastanza buono (ho un sacco di calze bianche senza alcun motivo), quindi diventa difficile. In tal caso, quale sarebbe il modo ottimale per farlo?
NothingsImpossible

56
@NothingsImpossibile è come si sentono gli attacchi di collisione di hash per un server web povero! Le calze bianche si distinguono per qualche attributo? Ci deve essere qualcosa su cui puoi distribuirli. Altrimenti, potresti semplicemente formare coppie arbitrariamente.
usr

37
Questo è un ordinamento Radix, che sono d'accordo è la risposta giusta. @MarkPeters Non penso che tu abbia bisogno di una tabella di ricerca. Un singolo passaggio lineare sui calzini può convertire i calzini in vettori numerici, rendendo banale la mappatura del "segmento di calzino". Le calze possono essere legate ai vettori con lo spago in modo da non aver bisogno di un altro passaggio lineare alla fine.
Punta il

49
Un ragazzo con cui sono andato al college aveva effettivamente PairIDs. È stato cucito su ogni paio di calzini con filo: 1, 2, 3, 4 ...
Ryan Lundy,

579

Poiché l'architettura del cervello umano è completamente diversa da una CPU moderna, questa domanda non ha senso pratico.

Gli umani possono conquistare algoritmi CPU utilizzando il fatto che "trovare una coppia corrispondente" può essere un'operazione per un set che non è troppo grande.

Il mio algoritmo:

spread_all_socks_on_flat_surface();
while (socks_left_on_a_surface()) {
     // Thanks to human visual SIMD, this is one, quick operation.
     pair = notice_any_matching_pair();
     remove_socks_pair_from_surface(pair);
}

Almeno questo è quello che sto usando nella vita reale, e lo trovo molto efficiente. Il rovescio della medaglia è che richiede una superficie piana, ma di solito è abbondante.


229
con l'aumentare del numero di calze, il SIMD umano non diventa migliore di una CPU.
Lie Ryan,

25
La migliore risposta, IMO. Mentre è divertente e intelligente (e appropriato per SO) ridurre un problema quotidiano a un algoritmo informatico, ha molto più senso usare il potere di risoluzione dell'occhio / cervello dell'uomo per un set piccolo come ~ 60 calze.
drug_user841417

13
@LieRyan Se le calze sono distribuite uniformemente, finirai per notare un paio in qualsiasi set di calze sufficientemente piccolo a causa del paradosso del compleanno (a meno che tu non possa distinguere i colori con precisione arbitraria, che dubito) quindi il collo di bottiglia qui non sarebbe l'algoritmo di corrispondenza del colore umano ma la fase di diffusione.
Thomas,

13
@ dpc.ucore.info No, perché hanno diversi modelli di polsini, lunghezze di polsino, lunghezze e sfumature di nero differenti (probabilmente mia moglie mi farebbe del male fisicamente per quest'ultima).
Christian,

200
Faresti meglio a sperare di avere un numero pari di calzini, altrimenti piegherai i calzini per molto tempo ...
Patrick James McDougle,

258

Caso 1 : tutte le calze sono identiche (questo è quello che faccio nella vita reale a proposito).

Scegline due per crearne una coppia. Tempo costante.

Caso 2 : esiste un numero costante di combinazioni (proprietà, colore, dimensioni, trama, ecc.).

Usa ordinamento radix . Questo è solo tempo lineare poiché il confronto non è richiesto.

Caso 3 : il numero di combinazioni non è noto in anticipo (caso generale).

Dobbiamo fare un confronto per verificare se due calzini vengono accoppiati. Scegli uno degli O(n log n)algoritmi di ordinamento basati sul confronto.

Tuttavia nella vita reale quando il numero di calze è relativamente piccolo (costante), questi algoritmi teoricamente ottimali non funzionerebbero bene. Potrebbe richiedere anche più tempo della ricerca sequenziale, che teoricamente richiede un tempo quadratico.


8
> Potrebbe richiedere anche più tempo della ricerca sequenziale, che in teoria richiede un tempo quadratico. Sì, è per questo che odio farlo, forse dovrei buttare via tutte le mie calze e iniziare con il caso 1.
Nils

57
il rovescio della medaglia di avere tutti i calzini identici è che tendono a invecchiare a velocità diverse. Quindi alla fine cerchi di abbinarli in base a quanto sono consumati. (che è più difficile della semplice corrispondenza per modello)
DSC

118
Il problema di avere 60 paia di calzini identici "perché facilita l'abbinamento" è che dà alle persone l'impressione che lavori con i computer.
Steve Ives,

13
Il caso 1 non è un tempo costante in cui è coinvolta un'operazione, come piegare le coppie insieme. In questo caso, è tempo lineare con il fattore costante più piccolo (la cui prova è lasciata come esercizio per il lettore). Non si può assolutamente fare lo stesso tempo piegando un paio e un secchio pieno di calzini. Tuttavia, si ridimensiona in modo lineare. Secondo la legge di Amdahl, ha una velocità illimitata, ignorando le spese generali. Secondo la legge di Gustafson, puoi piegare tutte le coppie necessarie per piegare una coppia dato un numero sufficiente di lavoratori (il cui importo viene lasciato come esercizio per il lettore), ignorando le spese generali.
acelent

7
@PauloMadeira L'ordinamento è un tempo costante: basta prendere la pila e metterla nel cassetto. L'unica operazione in questo caso è in realtà mettere le calze sui piedi, che è anche costante. La prestazione è ottenuta dall'esecuzione differita del calzino che indossa, possibilmente con un certo sacrificio nello spazio (lo spazio consumato dei calzini non piegati è più grande di quello piegato). Sostengo che ne valga la pena; Di solito perdo questa discussione con mia moglie.
Travis,

157

Risposta non algoritmica, ma "efficiente" quando lo faccio:

  • passaggio 1) scartare tutte le calze esistenti

  • passaggio 2) vai a Walmart e acquistali con pacchetti da 10 - n pacchetti di bianco e m pacchetti di nero. Non c'è bisogno di altri colori nella vita di tutti i giorni.

Eppure, a volte, devo farlo di nuovo (calzini persi, calzini danneggiati, ecc.), E odio scartare calzini perfettamente buoni troppo spesso (e avrei desiderato che continuassero a vendere lo stesso riferimento di calzini!), Quindi di recente ho preso un approccio diverso.

Risposta algoritmica:

Considera che se disegni una sola calza per la seconda pila di calze, mentre stai facendo, le tue probabilità di trovare la calza corrispondente in una ricerca ingenua sono abbastanza basse.

  • Quindi prendine cinque a caso e memorizza la loro forma o la loro lunghezza.

Perché cinque? Di solito gli umani sono bravi a ricordare tra cinque e sette diversi elementi nella memoria di lavoro - un po 'come l'equivalente umano di uno stack RPN - cinque è un default sicuro.

  • Prendi uno dalla pila di 2n-5.

  • Ora cerca una corrispondenza (corrispondenza del modello visivo - gli umani sono bravi a farlo con una piccola pila) all'interno dei cinque che hai disegnato, se non ne trovi uno, quindi aggiungilo ai tuoi cinque.

  • Continua a scegliere casualmente i calzini dallo stack e confrontali con i tuoi calzini 5 + 1 per una partita. Man mano che il tuo stack cresce, ridurrà le tue prestazioni ma aumenterà le tue probabilità. Più veloce.

Sentiti libero di scrivere la formula per calcolare quanti campioni devi pescare per una probabilità del 50% di una partita. IIRC è una legge ipergeometrica.

Lo faccio ogni mattina e raramente ho bisogno di più di tre pareggi - ma ho ncoppie simili (circa 10, dai o prendi quelle perse) di mcalzini bianchi sagomati. Ora puoi stimare la dimensione della mia pila di scorte :-)

A proposito , ho scoperto che la somma dei costi di transazione per ordinare tutti i calzini ogni volta che avevo bisogno di un paio era molto meno che farlo una volta e legare i calzini. Un just-in-time funziona meglio perché quindi non devi legare le calze e c'è anche un ritorno marginale decrescente (cioè, continui a cercare quelle due o tre calze che quando sei da qualche parte nella lavanderia e che ti servono per finire di abbinare le calze e perdere tempo).


25
Voto per risposta "non algoritmica". Questo è esattamente quello che faccio e funziona meravigliosamente. Il problema della sostituzione non è un problema se si "ruota" il proprio calzino posizionando le calze lavate sul retro e tirando dalla parte anteriore del cassetto al mattino. Tutte le calze si indossano uniformemente. Quando inizio a notare un po 'di usura su uno, inserisco la lista della spesa per sostituire completamente l'intera classe di calzini. Per i vecchi calzini, do il miglior 20% a Goodwill (legato in una sacca della spesa in modo che non si mescoli di nuovo) e lancio il resto. Non stai sprecando calze, a questo punto, l'80% ha comunque solo 6 mesi.
FastAl,

2
A proposito (1) Il legame dei calzini comporta che l'elastico venga riposto allungato e fallirà molto più rapidamente. Limitare i tipi di calzini unici che hai rende l'associazione senza segno. (2) Uno svantaggio di limitare calze uniche è che per le persone con determinati problemi di moda, il metodo potrebbe non essere adatto.
FastAl,

3
Sono venuto qui specificamente per pubblicare la tua risposta "non algoritmica". Come nella vera informatica, la maggior parte delle persone non presta mai sufficiente attenzione ai dati e alla sua struttura.
bkconrad,

Uso questo approccio algoritmico ogni mattina e funziona come un incantesimo! Inoltre, ho messo i calzini logori su una pila diversa da buttare via più tardi (sfortunatamente riescono a raggiungere di nuovo la pila originale prima di trovare il tempo di buttarla via).
Donatas Olsevičius,

3
«N pacchetto di bianco e m pacchetti di nero. Nessun bisogno di altri colori nella vita di tutti i giorni »Una buona regola standard per una facile selezione delle calze è in realtà che dovrebbero corrispondere al colore dei pantaloni o al colore della cintura. Per questo motivo, i colori più comunemente usati saranno probabilmente nero, blu, grigio e un po 'marrone. È difficile credere che uno abbia bisogno di molti calzini bianchi.
Andrea Lazzarotto,

106

Quello che faccio è che raccolgo il primo calzino e lo poso (diciamo, sul bordo del catino). Quindi raccolgo un altro calzino e controllo per vedere se è uguale al primo calzino. Se lo è, li rimuovo entrambi. In caso contrario, l'ho messo accanto al primo calzino. Quindi raccolgo il terzo calzino e lo confronto con i primi due (se sono ancora lì). Eccetera.

Questo approccio può essere facilmente implementato in un array, supponendo che la "rimozione" di calze sia un'opzione. In realtà, non è nemmeno necessario "rimuovere" le calze. Se non hai bisogno di ordinare i calzini (vedi sotto), puoi semplicemente spostarli e finire con un array che ha tutti i calzini disposti in coppie nell'array.

Supponendo che l'unica operazione per i calzini sia il confronto per uguaglianza, questo algoritmo è fondamentalmente ancora un algoritmo n 2 , anche se non conosco il caso medio (non ho mai imparato a calcolarlo).

L'ordinamento, ovviamente, migliora l'efficienza, soprattutto nella vita reale in cui è possibile "inserire" facilmente una calza tra altre due calze. Nel calcolo lo stesso potrebbe essere raggiunto da un albero, ma questo è uno spazio extra. E, naturalmente, torniamo a NlogN (o un po 'di più, se ci sono più calze uguali per criteri di ordinamento, ma non della stessa coppia).

A parte questo, non riesco a pensare a nulla, ma questo metodo sembra essere abbastanza efficace nella vita reale. :)


7
Questo è anche ciò che faccio (nota che se lasci semplicemente degli spazi, anche gli inserti sono O (1)), ma si ridimensionano male con un numero teoricamente elevato di calze.
Mooing Duck,

15
scala male con un numero teoricamente elevato di tipi di calzini
Steven Lu

@StevenLu - come ho detto - è n * n o nLogn, a seconda che tu lo ordini o meno. Quindi si ridimensiona meno di qualsiasi algoritmo di ordinamento. Se vuoi più velocemente, numerali e usa l'ordinamento radix.
Vilx-

Si tratta essenzialmente di memorizzare calze trovate ma non abbinate in una ricerca basata sull'hash. Con un hash ideale è O (n), ma se hai abbastanza calze memorizzate che l'hash inizia a degenerare, diventa di conseguenza più complesso.
Jon Hanna,

3
che valore fornisce l'inserimento di una calza tra altre 2 calze per l'obiettivo di accoppiare le calze? non esiste cardinalità delle calze. : -x
JoeBrockhaus,

60

Questa è la domanda sbagliata. La domanda giusta da porsi è: perché trascorro il tempo a selezionare i calzini? Quanto costa su base annuale, quando dai valore al tuo tempo libero per X unità monetarie di tua scelta?

E il più delle volte, questo non è solo qualsiasi tempo libero, che di mattina il tempo libero, che si potrebbe essere spesa a letto, o sorseggiando un caffè, o di lasciare un po 'presto e non essere catturati nel traffico.

Spesso è utile fare un passo indietro e pensare a come ovviare al problema.

E c'è un modo!

Trova un calzino che ti piace. Prendi in considerazione tutte le caratteristiche rilevanti: colore in diverse condizioni di illuminazione, qualità generale e durata, comfort in diverse condizioni climatiche e assorbimento degli odori. È anche importante che non debbano perdere elasticità durante lo stoccaggio, quindi i tessuti naturali sono buoni e dovrebbero essere disponibili in un involucro di plastica.

È meglio se non ci sono differenze tra i calzini per piede sinistro e destro, ma non è fondamentale. Se le calze sono simmetriche sinistra-destra, trovare una coppia è un'operazione O (1) e ordinare le calze è un'operazione O (M) approssimativa, dove M è il numero di posti nella tua casa, che hai disseminato di calze, idealmente alcuni piccolo numero costante.

Se hai scelto un paio di fantasia con diversi calzini sinistro e destro, eseguendo una sorta di secchio pieno sui secchi sinistro e destro prendi O (N + M), dove N è il numero di calzini e M è uguale a quello sopra. Qualcun altro può dare la formula per iterazioni medie di ricerca della prima coppia, ma il caso peggiore per trovare una coppia con ricerca cieca è N / 2 + 1, che diventa un caso astronomicamente improbabile per un ragionevole N. Questo può essere accelerato usando l'immagine avanzata algoritmi di riconoscimento ed euristica durante la scansione del mucchio di calze non ordinate con Mk1 Eyeball .

Quindi, un algoritmo per raggiungere l'efficienza di accoppiamento del calzino O (1) (supponendo calzino simmetrico) è:

  1. Devi stimare quante paia di calze avrai bisogno per il resto della tua vita, o forse fino a quando non ti ritirerai e ti trasferirai in climi più caldi senza la necessità di indossare mai più calze. Se sei giovane, potresti anche stimare quanto tempo ci vorrà prima che avremo tutti i robot di smistamento delle calze nelle nostre case e l'intero problema diventerà irrilevante.

  2. Devi scoprire in che modo puoi ordinare il calzino selezionato in blocco, quanto costa e come lo consegnano.

  3. Ordina le calze!

  4. Sbarazzati delle tue vecchie calze.

Un passaggio 3 alternativo comporterebbe il confronto dei costi di acquisto della stessa quantità di calzini forse più economici poche paia alla volta nel corso degli anni e l'aggiunta del costo di smistamento dei calzini, ma credetemi: comprarlo alla rinfusa è più economico! Inoltre, le calze nello stoccaggio aumentano di valore al tasso di inflazione dei prezzi delle azioni, che è più di quanto si otterrebbe su molti investimenti. Poi di nuovo c'è anche un costo di archiviazione, ma le calze in realtà non occupano molto spazio sul ripiano superiore di un armadio.

Problema risolto. Quindi, prendi solo nuovi calzini, butta / dona i tuoi vecchi e vivi per sempre felici e contenti sapendo che stai risparmiando tempo e denaro ogni giorno per il resto della tua vita.


Una fornitura a vita (presupponendo 75 anni) di calzini (supponendo che scarichi 4 paia / mese, che comporti 3600 paia) richiederebbe (supponendo che un nuovo paio di calzini occupi 20 pollici cubi) per un totale di 1 1/2 iarde cubiche. Questa è un'enorme quantità di spazio. Supponendo che te lo consegnino in una scatola che è approssimativamente un cubo, quella cassa sarà di circa 3 piedi e 4 pollici su un lato.
AJMansfield

2
@AJMansfield preoccupazione valida. Tuttavia, non sono d'accordo con alcuni dei tuoi numeri. Vorrei prendere un periodo di soli 40 anni (25 ... 65) (tempo tra il non vivere nei genitori / dormitorio / ecc. E il pensionamento, vedi sopra). Inoltre, penso che una coppia richieda più di 0,5x4x6 pollici nella confezione originale. Questi numeri riducono un po 'il tuo spazio estemporaneo!
hyde,

Il passaggio 4 è inutilmente inutile, -1.
Dan Bechard,

2
Guida per gli altri che potrebbero essere confusi dalle misurazioni di AJMansfield, una traduzione in metrica: »riprenderebbe (supponendo che un nuovo paio di calzini occupi 327 cm³) per un totale di 1,14 m³. Questa è un'enorme quantità di spazio. Supponendo che te lo consegnino in una scatola che è approssimativamente un cubo, quella cassa sarà di circa 1,04 m su un lato. «
Joey,

Come può una domanda basata sulla curiosità essere "la domanda sbagliata"? StackOverflow classico ...
Timmmm

52

Il limite teorico è O (n) perché è necessario toccare ogni calzino (a meno che alcuni non siano già associati in qualche modo).

Puoi ottenere O (n) con l' ordinamento radix . Devi solo selezionare alcuni attributi per i bucket.

  1. Per prima cosa puoi scegliere (la sua, la mia): dividerli in 2 pile,
  2. quindi usa i colori (può avere qualsiasi ordine per i colori, ad esempio in ordine alfabetico per nome del colore) - dividili in pile per colore (ricorda di mantenere l'ordine iniziale dal passaggio 1 per tutte le calze nella stessa pila),
  3. poi la lunghezza della calza,
  4. quindi trama, ....

Se puoi scegliere un numero limitato di attributi, ma abbastanza attributi che possono identificare in modo univoco ogni coppia, dovresti farlo in O (k * n), che è O (n) se possiamo considerare che k è limitato.


3
I calzini spesso sono disponibili in confezioni da 4 e più grandi, dal momento che sono più economici, ma ciò li rende anche indistinguibili. Per contrastare questo, mia moglie ha un piccolo segno su ogni nuovo paio di calze che compro. Il segno è di un colore diverso per ogni coppia o di una forma diversa, se esaurisce i colori. Con questo approccio non è nemmeno necessario un set limitato di attributi. Basta cucire un numero univoco su ciascuna coppia. :) Per punti extra, usa binario.
Vilx-

29
@ Vilx- PERCHÉ?!? Il punto è che non sono distinguibili?
flup,

2
@flup - Penso che il punto sia vendere in pacchetti più grandi. :) Quanto a me, questo aiuta a logorarli in coppia. Altrimenti posso finire con tre calzini molto consumati e uno nuovo di zecca. Un po 'sciocco.
Vilx-

13
Non sono d'accordo con il calcolo di O (n). Che cos'è $ k $? $ k $ è il numero di attributi. Direi che $ k $ è $ O (log n) $ perché deve essere sufficiente per identificare in modo univoco ogni coppia. Se hai 2 coppie (bianco e nero), è sufficiente il colore ($ k = 1, n = 2 $). Se hai un paio di neri, corti; un paio di neri, lunghi; un paio di bianco, corto; e una coppia di bianco, lungo - quindi $ k = 2, n = 4 $. Quindi se limitiamo $ k $, allo stesso tempo limitiamo $ n $. Se stiamo per limitare $ n $, il calcolo dell'ordine non ha più senso.
emory

3
@emory, penso che tu stia cercando il backtick, non il $personaggio, per far sembrare le tue cose in codice.
Xymostech,

33

Come soluzione pratica:

  1. Crea rapidamente pile di calzini facilmente distinguibili. (Dì per colore)
  2. Quicksort ogni pila e utilizzare la lunghezza della calza per il confronto. Come essere umano puoi prendere una decisione abbastanza veloce quale calzino usare per partizionare che evita il caso peggiore. (Puoi vedere più calze in parallelo, usale a tuo vantaggio!)
  3. Smetti di ordinare le pile quando hanno raggiunto una soglia in cui ti senti a tuo agio nel trovare istantaneamente coppie di punti e calzini spaiati

Se hai 1000 calze, con 8 colori e una distribuzione media, puoi creare 4 pile di ogni 125 calze in un tempo * c. Con una soglia di 5 calzini puoi ordinare ogni pila in 6 corse. (Contando 2 secondi per lanciare una calza sulla pila destra ci vorranno poco meno di 4 ore.)

Se hai solo 60 calzini, 3 colori e 2 tipi di calzini (tuoi / di tua moglie) puoi ordinare ogni pila di 10 calzini in 1 corsa (di nuovo soglia = 5). (Contando 2 secondi ci vorranno 2 minuti).

L'ordinamento iniziale dei bucket velocizzerà il tuo processo, perché divide i tuoi n socks in k secchi in c*ntempo, quindi dovrai solo c*n*log(k)lavorare. (Non tenendo conto della soglia). Quindi, tutto sommato, fai del n*c*(1 + log(k))lavoro, dove c è il momento di gettare un calzino su una pila.

Questo approccio sarà favorevole rispetto a qualsiasi c*x*n + O(1)metodo all'incirca finché log(k) < x - 1.


In informatica ciò può essere utile: abbiamo una raccolta di n cose , un ordine su di esse (lunghezza) e anche una relazione di equivalenza (informazioni extra, ad esempio il colore dei calzini). La relazione di equivalenza ci consente di creare una partizione della collezione originale e in ogni classe di equivalenza il nostro ordine è ancora mantenuto. La mappatura di una cosa alla sua classe di equivalenza può essere fatta in O (1), quindi è necessario solo O (n) per assegnare ciascun oggetto a una classe. Ora abbiamo usato le nostre informazioni extra e possiamo procedere in qualsiasi modo per ordinare ogni classe. Il vantaggio è che i set di dati sono già significativamente più piccoli.

Il metodo può anche essere nidificato, se abbiamo più relazioni di equivalenza -> crea pile di colori, che all'interno di ogni partizione di pila sulla trama, che ordina per lunghezza. Qualsiasi relazione di equivalenza che crea una partizione con più di 2 elementi che hanno dimensioni pari a circa porterà un miglioramento della velocità rispetto all'ordinamento (a condizione che possiamo assegnare direttamente un calzino alla sua pila) e l'ordinamento può avvenire molto rapidamente su set di dati più piccoli.


3
Ottimizzazione umana: direi che come umano, per il passaggio 2, dovresti abbattere i calzini in ordine approssimativamente crescente, quindi ripetere con granularità sempre più fine fino a quando non vengono ordinati, un po 'come l'ordinamento delle conchiglie. Questo sarebbe molto più veloce per un umano (stima visiva) rispetto a un approccio basato sul confronto-swap.
AndrewC,

28

Stai cercando di risolvere il problema sbagliato.

Soluzione 1: ogni volta che mettete dei calzini sporchi nel cesto della biancheria, annodateli con un nodo. In questo modo non dovrai fare alcun ordinamento dopo il lavaggio. Pensalo come registrare un indice in un database Mongo. Un piccolo lavoro in anticipo per alcuni risparmi della CPU in futuro.

Soluzione 2: se è inverno, non è necessario indossare calze abbinate. Siamo programmatori. Nessuno ha bisogno di sapere, finché funziona.

Soluzione 3: diffondere il lavoro. Volete eseguire un processo CPU così complesso in modo asincrono, senza bloccare l'interfaccia utente. Prendi quel mucchio di calzini e mettili in una borsa. Cerca un paio solo quando ne hai bisogno. In questo modo la quantità di lavoro necessaria è molto meno evidente.

Spero che sia di aiuto!


5
Legare i calzini (o tutti gli indumenti) in un nodo riduce la capacità della lavatrice di lavare gli indumenti e rende lo scioglimento per indossarli molto più difficili. La soluzione 2 rende più difficile la manutenzione man mano che avanza lo stato delle cose; dopo 6 mesi, quando hai bisogno di due calzini neri alla caviglia da indossare con un paio di pantaloncini e scarpe da ginnastica, 6 mesi di lavoro qualunque faranno trovare quel paio nelle stesse condizioni (sporco / pulito, abbigliamento simile) molto meno probabile. La soluzione 3 è meno "asincrona" e più semplice "pigra"; fare il lavoro minimo necessario esattamente quando è necessario.
KeithS

Ri: soluzione 2: la gente saprà che non indosso calzini abbinati perché li vedranno nella mia Birks :)
Bob Probst,

@BobProbst Sì, ma i tuoi colleghi programmatori indosseranno anche calzini senza pari con Birks e quindi saranno felici di notare che non sono i soli.
Francesco Pasa,

27

Questa domanda è in realtà profondamente filosofica. Fondamentalmente si tratta di stabilire se il potere delle persone di risolvere i problemi (il "wetware" del nostro cervello) equivale a ciò che può essere realizzato con gli algoritmi.

Un ovvio algoritmo per l'ordinamento dei calzini è:

Let N be the set of socks that are still unpaired, initially empty
for each sock s taken from the dryer
  if s matches a sock t in N
    remove t from N, bundle s and t together, and throw them in the basket
  else
    add s to N

Ora l'informatica in questo problema riguarda tutti i passaggi

  1. "se s si accoppia con una calza t in N". Quanto velocemente possiamo "ricordare" ciò che abbiamo visto finora?
  2. "rimuovi t da N" e "aggiungi s a N". Quanto costa tenere traccia di ciò che abbiamo visto finora?

Gli esseri umani useranno varie strategie per realizzarle. La memoria umana è associativa , qualcosa di simile a una tabella hash in cui set di funzionalità di valori memorizzati sono associati ai valori corrispondenti stessi. Ad esempio, il concetto di "macchina rossa" è associato a tutte le macchine rosse che una persona è in grado di ricordare. Qualcuno con una memoria perfetta ha una mappatura perfetta. La maggior parte delle persone è imperfetta in questo senso (e la maggior parte degli altri). La mappa associativa ha una capacità limitata. Le mappature possono essere sospese fuori dall'esistenza in varie circostanze (una birra di troppo), essere registrato per errore ("Pensavo che il suo nome fosse Betty, non Nettie"), o mai essere sovrascritto anche se osserviamo che la verità è cambiata ("la macchina di papà" evoca "arancione Firebird" quando sapevamo che lo aveva scambiato con il rosso Camaro).

Nel caso dei calzini, il richiamo perfetto significa che guardare un calzino sproduce sempre la memoria del fratello t, comprese informazioni sufficienti (dove si trova sull'asse da stiro) per localizzarlo tin tempo costante. Una persona con memoria fotografica compie sia 1 che 2 in tempo costante a colpo sicuro.

Qualcuno con una memoria tutt'altro che perfetta potrebbe usare alcune classi di equivalenza di buon senso basate su caratteristiche all'interno della sua capacità di tracciare: dimensioni (papa, mamma, bambino), colore (verdastro, rossastro, ecc.), Modello (argyle, pianura, ecc.) , stile (footie, gambaletto, ecc.). Quindi l'asse da stiro sarebbe diviso in sezioni per le categorie. Questo di solito consente alla categoria di essere posizionata in tempo costante dalla memoria, ma è quindi necessaria una ricerca lineare attraverso la categoria "bucket".

Qualcuno senza memoria o immaginazione (scusate) manterrà le calze in una pila e farà una ricerca lineare dell'intera pila.

Un mostro ordinato potrebbe usare etichette numeriche per le coppie come qualcuno ha suggerito. Questo apre le porte a un ordinamento totale, che consente all'essere umano di utilizzare esattamente gli stessi algoritmi che potremmo avere con una CPU: ricerca binaria, alberi, hash, ecc.

Quindi l'algoritmo "migliore" dipende dalle qualità del wetware / hardware / software che lo sta eseguendo e dalla nostra volontà di "imbrogliare" imponendo un ordine totale sulle coppie. Certamente un "miglior" meta- algoritmo è assumere il selezionatore di calzini migliore del mondo: una persona o una macchina che può acquisire e immagazzinare rapidamente un enorme set di set di attributi di calzino in una memoria associativa 1-1 con ricerca del tempo costante, inserire, ed elimina. Sia le persone che le macchine come questa possono essere acquistate. Se ne hai uno, puoi accoppiare tutti i calzini in O (N) per N coppie, il che è ottimale. I tag di ordine totale consentono di utilizzare l'hash standard per ottenere lo stesso risultato con un computer umano o hardware.


Ok, va meglio, anche se è ancora del tutto sbagliato ... questa domanda non riguarda questo. Se la tesi di Church-Turing è corretta, sia gli umani che i nostri computer possono ordinare i calzini. (La realtà è che gli esseri umani, essendo entità altamente finite, hanno molto meno potere computazionale rispetto alle Macchine di Turing ... e lo stesso vale per i nostri computer, ma i limiti sono diversi.)
Jim Balter

Non sono d'accordo. Naturalmente uno dei nostri computer attuali è essenzialmente ed enorme DFA (differenze modulo i / o) piuttosto che un TM. Qualsiasi dispositivo analogico, tuttavia, come i nostri corpi, è in grado di emulare un nastro infinito. Non abbiamo ancora un'utile caratterizzazione del modo in cui le nostre menti calcolano.
Gene

Nessun nastro infinito per l'uomo o altri dispositivi fisici perché nulla nel cervello umano ha una risoluzione infinita, né potrebbe. Aiuterebbe anche ad imparare alcune neuroscienze. In ogni caso, non c'era una profonda domanda filosofica qui, indipendentemente dal tuo desiderio di iniettarne una. Ma credi a quello che vuoi ... questo non è il posto per questo tipo di dibattito e l'ho già avuto troppe volte. Ma sono sempre divertito da persone che riescono a malapena a risolvere i problemi più semplici (tutti noi) immaginando che siano equivalenti alla MT.
Jim Balter,

22

Costo: spostamento dei calzini -> alti, ricerca / ricerca di calzini in linea -> piccoli

Quello che vogliamo fare è ridurre il numero di mosse e compensare con il numero di ricerche. Inoltre, possiamo utilizzare l'ambiente multithreded dell'Homo Sapiens per contenere più elementi nella cache di descrizione.

X = Tuo, Y = I tuoi coniugi

Dal mucchio A di tutte le calze:

Scegli due calzini, posiziona il calzino X corrispondente nella linea X e il calzino Y nella linea Y nella successiva posizione disponibile.

Fallo fino a quando A è vuoto.

Per ogni riga X e Y

  1. Scegli la prima calza in linea, cerca lungo la linea fino a trovare la calza corrispondente.

  2. Inserire nella corrispondente linea finita di calze.

  3. Facoltativo Mentre stai cercando la linea e la calza attuale che stai osservando è identica alla precedente, esegui il passaggio 2 per queste calze.

Facoltativamente al primo passaggio, prendi due calzini da quella linea anziché due, poiché la memoria della cache è abbastanza grande che possiamo identificare rapidamente se uno dei calzini corrisponde a quello attuale sulla linea che stai osservando. Se sei abbastanza fortunato da avere tre braccia, potresti eventualmente analizzare tre calze allo stesso tempo, dato che la memoria del soggetto è abbastanza grande.

Fallo fino a quando sia X che Y sono vuoti.

Fatto

Tuttavia, poiché ciò ha una complessità simile a quella dell'ordinamento selettivo, il tempo impiegato è molto inferiore a causa della velocità di I / O (spostamento dei calzini) e della ricerca (ricerca della linea per un calzino).


22

Ecco un limite inferiore Omega (n log n) nel modello basato sul confronto. (L'unica operazione valida è quella di confrontare due calzini.)

Supponi di sapere che le tue calze 2n sono disposte in questo modo:

p 1 p 2 p 3 ... p n p f (1) p f (2) ... p f (n)

dove f è una permutazione sconosciuta dell'insieme {1,2, ..., n}. Sapere questo non può rendere il problema più difficile. Non ci sono! possibili output (corrispondenze tra la prima e la seconda metà), il che significa che è necessario il confronto log (n!) = Omega (n log n). Questo è ottenibile ordinando.

Dato che sei interessato alle connessioni al problema della distinzione tra elementi: dimostrare che Omega (n log n) è associato alla distinzione tra elementi è più difficile, perché l'output è sì / no binario. Qui, l'uscita deve essere una corrispondenza e il numero di possibili uscite è sufficiente per ottenere un limite decente. Tuttavia, esiste una variante connessa alla distinzione tra elementi. Supponiamo che ti vengano dati 2 calzini e chiedi se possono essere accoppiati in modo univoco. Puoi ottenere una riduzione da ED inviando (a 1 , a 2 , ..., a n ) a (a 1 , a 1 , a 2 , a 2 , ..., a n , a n ). (Tra parentesi, la prova della durezza dell'ED è molto interessante, tramite la topologia.)

Penso che dovrebbe esserci un Omega (n 2 ) associato al problema originale se si consentono solo test di uguaglianza. La mia intuizione è: considera un grafico in cui aggiungi un bordo dopo un test e sostiene che se il grafico non è denso, l'output non viene determinato in modo univoco.


19

Questo è come io in realtà faccio, per p paia di calzini ( n = 2p singoli calze):

  • Prendi una calza a caso dalla pila.
  • Per il primo calzino, o se tutti i calzini scelti in precedenza sono stati accoppiati, posiziona semplicemente il calzino nel primo "slot" di un "array" di calzini spaiati di fronte a te.
  • Se hai selezionato uno o più calzini non accoppiati selezionati, controlla il calzino attuale con tutti i calzini non accoppiati dell'array.
    • È possibile separare i calzini in classi o tipi generali (bianco / nero, caviglia / equipaggio, atletica / vestito) durante la costruzione dell'array e "drill-down" per confrontare solo like-for-like.
    • Se trovi una corrispondenza accettabile, metti insieme entrambi i calzini e rimuovili dall'array.
    • In caso contrario, inserire la calza corrente nel primo slot aperto dell'array.
  • Ripeti con ogni calza.

Lo scenario peggiore di questo schema è che ogni paio di calzini è abbastanza diverso da corrispondere esattamente e che i primi calzini n / 2 che scegli sono tutti diversi. Questo è il tuo scenario O (n 2 ) ed è estremamente improbabile. Se il numero di tipi unici di calzino t è inferiore al numero di paia p = n / 2 e i calzini di ciascun tipo sono abbastanza simili (di solito in termini di usura) che qualsiasi calzino di quel tipo può essere accoppiato con qualsiasi altro, quindi, come ho dedotto in precedenza, il numero massimo di calze che dovrai mai confrontare è t , dopo di che il prossimo che tirerai saràabbinare uno dei calzini spaiati. Questo scenario è molto più probabile nel cassetto delle calze medio rispetto al caso peggiore e riduce la complessità del caso peggiore a O (n * t) dove di solito t << n .


1
Questo è probabilmente abbastanza vicino al mio processo mentale. Ho un ulteriore livello di ottimizzazione pre-ordinamento. Le mie calze da ginnastica vengono lavate con i bianchi e le calze da vestito vengono lavate con i colori. Ciò significa che fino a quando non scarico due carichi di biancheria insieme, le mie calze sono già raggruppate per tipo. Il carico bianco procede molto velocemente (molti calzini identici) ma i calzini del vestito impiegano più tempo. Altro suggerimento chiave: rendi più disponibile la memoria per l'ordinamento (piega e rimuovi prima tutte le non calze e POI esegui l'algoritmo di associazione)
orh

17

Approccio nel mondo reale:

Il più rapidamente possibile, rimuovi i calzini dalla pila non ordinata uno alla volta e mettili in pile di fronte a te. Le pile dovrebbero essere disposte in modo un po 'efficiente nello spazio, con tutte le calze che puntano nella stessa direzione; il numero di pile è limitato dalla distanza facilmente raggiungibile. La scelta di una pila su cui mettere una calza dovrebbe essere - il più rapidamente possibile - mettendo una calza su una pila di calzini apparentemente simili; si può tollerare l'errore occasionale di tipo I (mettere una calza su una pila a cui non appartiene) o di tipo II (mettere una calza nella propria pila quando esiste una pila di calzini simili) - la considerazione più importante è la velocità .

Una volta che tutte le calze sono in pile, passa rapidamente attraverso le pile multi-calza creando coppie e rimuovendole (queste sono dirette al cassetto). Se ci sono calzini non corrispondenti nella pila, raggruppali nuovamente nella pila migliore (entro il limite del più veloce possibile). Quando tutte le pile multi-calzino sono state elaborate, abbinare le calze accoppiabili rimanenti che non sono state accoppiate a causa di errori di tipo II. Whoosh, hai finito - e ho un sacco di calzini e non li lavo fino a quando una grande frazione è sporca. Un'altra nota pratica: capovolgo la parte superiore di uno di un paio di calzini sull'altro, sfruttando le loro proprietà elastiche, in modo che rimangano uniti mentre vengono trasportati nel cassetto e mentre sono nel cassetto.


15

Dalla tua domanda è chiaro che non hai molta esperienza reale con il bucato :). È necessario un algoritmo che funzioni bene con un numero limitato di calze non accoppiabili.

Le risposte fino ad ora non fanno buon uso delle nostre capacità di riconoscimento dei modelli umani. Il gioco di Set fornisce un indizio su come farlo bene: metti tutte le calze in uno spazio bidimensionale in modo da poterle riconoscere bene e raggiungerle facilmente con le mani. Questo ti limita a un'area di circa 120 * 80 cm circa. Da lì seleziona le coppie che riconosci e rimuovile. Metti le calze extra nello spazio libero e ripeti. Se ti lavi per le persone con calzini facilmente riconoscibili (i bambini piccoli vengono in mente), puoi fare un ordinamento radix selezionando prima quelle calze. Questo algoritmo funziona bene solo quando il numero di calze singole è basso


Di solito è così che lo faccio. Funziona molto meglio di ripetere ogni volta tutte le calze rimanenti.
yu_ominae,

Un approccio gradevole e penso che possa essere applicato anche ad alcuni problemi di CS reali. Potete per favore aggiungere un esempio di questo (un problema CS in cui potremmo usare un approccio simile per risolvere i problemi)? Inoltre, come si adatta questa soluzione per milioni di calze?
Amit

Penso che sia sostanzialmente la stessa dell'altra risposta qui, stackoverflow.com/a/14423956 , del 20 gennaio. Entrambi +1. Il sistema di visione umana è enormemente parallelo.
Will Ness,

15

Prendi un primo calzino e mettilo su un tavolo. Ora scegli un altro calzino; se corrisponde al primo selezionato, posizionalo sopra al primo. In caso contrario, posizionalo sul tavolo a una piccola distanza dal primo. Scegli un terzo calzino; se corrisponde a uno dei due precedenti, posizionalo sopra di essi oppure posizionalo a una piccola distanza dal terzo. Ripeti finché non avrai raccolto tutti i calzini.


1
Questa è l'unica risposta valida. Tutti gli altri ignorano il fatto che trascorre la maggior parte del tempo a distinguere tra calzini simili (quindi aggrapparli tutti insieme dall'aspetto fisico rende ancora peggio).
entonio,

Per divertimento ho scritto questo metodo per accumulare calze in un piccolo programma di pitone gist.github.com/justinfay/53b574cf0a492f6795ef
Justin Fay

12

Per dire quanto sia efficace accoppiare i calzini da una pila, dobbiamo prima definire la macchina, perché l'accoppiamento non viene effettuato né da un turing né da una macchina ad accesso casuale, che sono normalmente utilizzate come base per un analisi algoritmica.

La macchina

La macchina è un'astrazione di un elemento del mondo reale chiamato essere umano. È in grado di leggere dall'ambiente tramite un paio di occhi. E il nostro modello di macchina è in grado di manipolare l'ambiente utilizzando 2 bracci. Le operazioni logiche e aritmetiche sono calcolate usando il nostro cervello (si spera ;-)).

Dobbiamo anche considerare la durata intrinseca delle operazioni atomiche che possono essere eseguite con questi strumenti. A causa di vincoli fisici, le operazioni eseguite da un braccio o da un occhio presentano una complessità temporale non costante. Questo perché non possiamo spostare un mucchio infinitamente grande di calzini con un braccio né un occhio può vedere il calzino superiore su un mucchio infinitamente grande di calzini.

Tuttavia, anche la fisica meccanica ci offre alcuni vantaggi. Non ci limitiamo a muovere al massimo una calza con un braccio. Possiamo spostarne un paio intero in una volta.

Pertanto, a seconda dell'analisi precedente, le seguenti operazioni devono essere utilizzate in ordine decrescente:

  • operazioni logiche e aritmetiche
  • letture ambientali
  • modifiche ambientali

Possiamo anche sfruttare il fatto che le persone hanno solo un numero molto limitato di calze. Quindi una modifica ambientale può coinvolgere tutti i calzini nella pila.

L'algoritmo

Quindi ecco il mio suggerimento:

  1. Distribuisci tutti i calzini nella pila sul pavimento.
  2. Trova un paio guardando le calze sul pavimento.
  3. Ripetere da 2 fino a quando non è possibile effettuare alcuna coppia.
  4. Ripeti da 1 fino a quando non ci sono calze sul pavimento.

L'operazione 4 è necessaria, perché quando si distribuiscono le calze sul pavimento alcune calze potrebbero nasconderne altre. Ecco l'analisi dell'algoritmo:

Le analisi

L'algoritmo termina con alta probabilità. Ciò è dovuto al fatto che non è possibile trovare paia di calze nel passaggio numero 2.

Per la seguente analisi di runtime di accoppiamento di npaia di calze, supponiamo che almeno la metà delle 2ncalze non sia nascosta dopo il passaggio 1. Quindi, nel caso medio, possiamo trovare n/2coppie. Ciò significa che il ciclo è il passo 4 viene eseguito O(log n)volte. Il passaggio 2 è eseguito O(n^2)volte. Quindi possiamo concludere:

  • L'algoritmo prevede O(ln n + n)modifiche ambientali (fase 1 O(ln n)più raccolta di ogni paio di calze dal pavimento)
  • L'algoritmo prevede O(n^2)letture ambientali dal passaggio 2
  • L'algoritmo prevede O(n^2)operazioni logiche e aritmetiche per confrontare un calzino con un altro nel passaggio 2

Quindi abbiamo una complessità di runtime totale di O(r*n^2 + w*(ln n + n))dove re wsono i fattori per le operazioni di lettura ambientale e di scrittura ambientale rispettivamente per un numero ragionevole di calze. Il costo delle operazioni logiche e aritmetiche viene omesso, perché supponiamo che ci voglia una quantità costante di operazioni logiche e aritmetiche per decidere se 2 calze appartengono alla stessa coppia. Questo potrebbe non essere fattibile in tutti gli scenari.



@WillNess Yep, con un po 'più di spiegazioni
SpaceTrucker

12
List<Sock> UnSearchedSocks = getAllSocks();
List<Sock> UnMatchedSocks = new list<Sock>();
List<PairOfSocks> PairedSocks = new list<PairOfSocks>();

foreach (Sock newSock in UnsearchedSocks)
{
  Sock MatchedSock = null;
  foreach(Sock UnmatchedSock in UnmatchedSocks)
  {
    if (UnmatchedSock.isPairOf(newSock))
    {
      MatchedSock = UnmatchedSock;
      break;
    }
  }
  if (MatchedSock != null)
  {
    UnmatchedSocks.remove(MatchedSock);
    PairedSocks.Add(new PairOfSocks(MatchedSock, NewSock));
  }
  else
  {
    UnmatchedSocks.Add(NewSock);
  }
}

12

Sono uscito con un'altra soluzione che non prometterebbe un minor numero di operazioni, né un minor consumo di tempo, ma dovrebbe essere provato a vedere se può essere un buon euristico per fornire un minor consumo di tempo in enormi serie di accoppiamenti di calze.

Presupposti: non esiste alcuna garanzia che esistano le stesse calze. Se sono dello stesso colore, ciò non significa che abbiano le stesse dimensioni o lo stesso motivo. I calzini vengono mescolati casualmente. Può esserci un numero dispari di calze (alcune mancano, non sappiamo quante). Preparati a ricordare un "indice" variabile e impostalo su 0.

Il risultato avrà una o due pile: 1. "abbinato" e 2. "mancante"

Euristico:

  1. Trova la calza più distintiva.
  2. Trova la sua corrispondenza.
  3. Se non c'è partita, mettila nella pila "mancante".
  4. Ripeti dal 1. fino a quando non ci sono più calzini più distintivi.
  5. Se ci sono meno di 6 calze, vai a 11.
  6. Abbina ciecamente tutte le calze al vicino (non imballarlo)
  7. Trova tutte le coppie abbinate, impacchettalo e sposta le coppie impaccate nella pila "abbinata"; Se non ci sono nuove corrispondenze, incrementa "indice" di 1
  8. Se "indice" è maggiore di 2 (questo potrebbe dipendere dal valore in base al numero del calzino perché con un numero maggiore di calzini ci sono meno possibilità di abbinarli ciecamente) vai a 11
  9. Mescola il resto
  10. Vai a 1
  11. Dimentica "indice"
  12. Scegli un calzino
  13. Trova la sua coppia
  14. Se non ci sono coppie per la calza, spostala nella pila "mancante"
  15. Se la corrispondenza trovata la accoppia, impacchetta la coppia e la sposta nella pila "abbinata"
  16. Se ce ne sono ancora più di una, vai a 12
  17. Se è rimasto solo uno, vai a 14
  18. Sorriso soddisfatto :)

Inoltre, potrebbe essere aggiunto verificare anche la presenza di calze danneggiate, come se la rimozione di quelle. Potrebbe essere inserito tra 2 e 3 e tra 13 e 14.

Non vedo l'ora di conoscere eventuali esperienze o correzioni.


Dopo averlo scritto, lo uso ogni volta. Mi ha aiutato a diventare un po 'più efficiente e il lavoro ora è meno noioso.
Sasa,

11

Quando ordino i calzini, eseguo un ordinamento radix approssimativo , facendo cadere calzini vicino ad altri calzini dello stesso tipo di colore / modello. Tranne nel caso in cui riesco a vedere una corrispondenza esatta in / vicino alla posizione che sto per rilasciare la calza, estraggo la coppia in quel punto.

Quasi tutti gli altri algoritmi (inclusa la risposta di punteggio superiore di usr ) ordinano, quindi rimuovono le coppie. Trovo che, come essere umano, sia meglio ridurre al minimo il numero di calze considerate contemporaneamente.

Lo faccio per:

  1. Scegliere una calza distintiva (qualunque cosa attiri per prima cosa nella pila).
  2. Iniziare una specie di radix da quella posizione concettuale estraendo i calzini dalla pila in base alla somiglianza con quello.
  3. Posiziona la nuova calza vicino alla pila attuale, con una distanza basata su quanto è diversa. Se ti ritrovi a mettere il calzino sopra l'altro perché è identico, forma la coppia lì e rimuovili. Ciò significa che i confronti futuri richiedono meno sforzi per trovare il posto giusto.

Questo sfrutta la capacità umana di fuzzy-match nel tempo O (1), che è in qualche modo equivalente alla creazione di una mappa hash su un dispositivo di elaborazione.

Tirando prima i calzini distintivi, si lascia spazio per "ingrandire" le caratteristiche che sono meno distintive, per cominciare.

Dopo aver eliminato il colore fluro, i calzini a strisce e le tre paia di calzini lunghi, potresti ritrovarti con calzini per lo più bianchi approssimativamente ordinati in base a quanto sono consumati.

Ad un certo punto, le differenze tra i calzini sono abbastanza piccole che le altre persone non noteranno la differenza e non sono necessari ulteriori sforzi di abbinamento.


10

Ogni volta che raccogli un calzino, mettilo in un posto. Quindi il calzino successivo che raccogli, se non corrisponde al primo calzino, posizionalo accanto al primo. Se lo fa, ce n'è un paio. In questo modo non importa davvero quante combinazioni ci siano e ci sono solo due possibilità per ogni calzino che raccogli: o ha una corrispondenza che è già nella tua gamma di calzini, oppure no, il che significa che aggiungilo a un posto nell'array.

Questo significa anche che quasi sicuramente non avrai mai tutte le calze nell'array, perché le calze verranno rimosse quando vengono abbinate.


Questo è quello che faccio ... O (n)
Pykler

2
@Pykler - È O (n) nel migliore dei casi e O (n * n) nel peggiore dei casi.
Vilx-

2
Ciò presuppone che non puoi creare un hash completamente unico nella tua mente di tutti i calzini che hai già visto, che per me è una O (1) per abbinare un calzino che ho visto e precedentemente e messo in attesa di abbinare l' hash
Pykler

10

Considera una tabella hash di dimensioni 'N'.

Se assumiamo una distribuzione normale, il numero stimato di "inserimenti" per avere almeno un calzino mappato su un bucket è NlogN (ovvero, tutti i bucket sono pieni)

Ne avevo ricavato come parte di un altro enigma, ma sarei felice di essere smentito. Ecco il mio articolo sul blog sullo stesso

Lascia che 'N' corrisponda a un limite superiore approssimativo sul numero di colori / motivi unici di calze che hai.

Una volta che hai una collisione (aka: una partita), rimuovi semplicemente quel paio di calzini. Ripeti lo stesso esperimento con il prossimo lotto di calze NlogN. Il bello è che potresti fare paragoni paralleli di NlogN (risoluzione delle collisioni) a causa del modo in cui funziona la mente umana. :-)


10

I calzini, siano essi reali o una struttura dati analoga, verrebbero forniti in coppia.

La risposta più semplice è prima di consentire la separazione della coppia, una singola struttura di dati per la coppia avrebbe dovuto essere inizializzata che conteneva un puntatore alla calza sinistra e destra, consentendo così di fare riferimento alle calze direttamente o tramite la loro coppia. Una calza può anche essere estesa per contenere un puntatore al suo partner.

Ciò risolve qualsiasi problema di accoppiamento computazionale rimuovendolo con uno strato di astrazione.

Applicando la stessa idea al problema pratico dell'abbinamento dei calzini, la risposta apparente è: non permettere che i tuoi calzini siano mai spaiati. I calzini sono forniti in coppia, messi nel cassetto in coppia (forse unendoli insieme), indossati in coppia. Ma il punto in cui è possibile l'abbinamento è nella lavatrice, quindi tutto ciò che serve è un meccanismo fisico che consenta alle calze di stare insieme e di essere lavate in modo efficiente.

Esistono due possibilità fisiche:

Per un oggetto "coppia" che mantiene un puntatore su ogni calza potremmo avere una borsa di stoffa che usiamo per tenere insieme i calzini. Sembra un enorme sovraccarico.

Ma per ogni calzino per mantenere un riferimento all'altro, esiste una soluzione ordinata: un bottone automatico (o un 'pulsante a scatto' se sei americano), come questi:

http://www.aliexpress.com/compare/compare-invisible-snap-buttons.html

Quindi tutto ciò che fai è agganciare le calze subito dopo averle tolte e metterle nel cestello del lavaggio, e di nuovo hai rimosso il problema di dover accoppiare le calze con un'astrazione fisica del concetto di "coppia".


Non risponde alla domanda, poiché la gestione con dati già associati è semplice, la domanda è cosa fare quando i dati sono NON PAESI e si desidera abbinarli.
Amit

8

Se l'operazione "sposta" è piuttosto costosa e l'operazione "confronta" è economica e devi comunque spostare l'intero set in un buffer in cui la ricerca è molto più veloce rispetto alla memoria originale ... basta integrare l'ordinamento nell'obbligatorio mossa.

Ho scoperto che integrare il processo di smistamento in appeso ad asciugare lo rende un gioco da ragazzi. Devo comunque raccogliere ogni calzino e appenderlo (muoverlo) e non mi costa nulla appenderlo in un punto specifico sulle corde. Ora, solo per non forzare la ricerca dell'intero buffer (le stringhe), ho scelto di posizionare i calzini per colore / tonalità. Più scuro a sinistra, più luminoso a destra, più colorato davanti ecc. Ora prima di appendere ogni calzino, guardo nella sua "giusta vicinanza" se ne esiste già uno corrispondente - questo limita la "scansione" ad altri 2-3 calzini - e se lo è , Appendo l'altro proprio accanto ad esso. Quindi li arrotolo a coppie mentre lo rimuovo dalle corde, quando sono asciutti.

Ora, questo potrebbe non sembrare molto diverso dal "formare pile per colore" suggerito dalle risposte migliori ma prima, non scegliendo pile discrete ma intervalli, non ho problemi a classificare se "viola" va a "rosso" o "blu"; va solo in mezzo. E poi integrando due operazioni (appendere ad asciugare e ordinare) l'overhead dello smistamento mentre appeso è come il 10% di quello che sarebbe lo smistamento separato.


Questo approccio presenta altri due vantaggi: l'asciugatura della linea perde un numero inferiore di calze IME rispetto all'asciugatrice e il processo di smistamento può essere esteso al resto della biancheria, quindi (ad esempio) tutti gli asciugamani sono vicini l'uno all'altro per essere ripiegati linea e si incastonò e portò direttamente al loro deposito. Funziona anche in due passaggi a basso sforzo, rimettendo i vestiti e togliendoli di nuovo.
cphlewis,

8

Ho finito di abbinare le mie calze proprio ora e ho scoperto che il modo migliore per farlo è il seguente:

  • Scegli una delle calze e mettila via (crea un 'secchio' per quella coppia)
  • Se il successivo è la coppia di quello precedente, inseriscilo nel bucket esistente, altrimenti creane uno nuovo.

Nel peggiore dei casi significa che avrai n / 2 secchi diversi e avrai n-2 determinazioni su ciò che bucket contiene la coppia della calza corrente. Ovviamente, questo algoritmo funziona bene se hai solo poche coppie; L'ho fatto con 12 coppie.

Non è così scientifico, ma funziona bene :)


Questo è ancora un algoritmo O (n ^ 2) poiché devi scorrere su ogni bucket ogni volta che estrai una nuova calza. Ma, considerando il fatto che anche i calzini acquistati nello stesso lotto presentano differenze minori che li rendono effettivamente univoci (o addirittura univoci), non c'è modo migliore comunque
Semisonic,

D'accordo, ma il mio algoritmo presuppone che l'umano stia facendo l'accoppiamento. Pertanto, ci sarà un tipo di cache nella tua mente quando stai cercando il bucket corrispondente, quindi non devi davvero iterare sui bucket in ogni caso. Non sono sicuro di quale tipo di struttura dati sia stata creata per questo meccanismo di memorizzazione nella cache nella mia testa durante l'associazione.
maestro

8

La mia soluzione non corrisponde esattamente alle tue esigenze, in quanto richiede formalmente O(n)spazio "extra". Tuttavia, considerando le mie condizioni, è molto efficace nella mia applicazione pratica. Quindi penso che dovrebbe essere interessante.

Combina con altre attività

La condizione speciale nel mio caso è che non uso asciugatrice, appendo semplicemente i miei panni su un normale asciugabiancheria. I panni appesi richiedono O(n)operazioni (a proposito, qui considero sempre il problema dell'imballaggio del cestino ) e il problema per sua natura richiede lo spazio "extra" lineare. Quando prendo una nuova calza dal secchio, provo ad appenderla accanto alla sua coppia se la coppia è già appesa. Se è una calza da una nuova coppia, lascio un po 'di spazio accanto.

Oracle Machine is Better ;-)

Richiede ovviamente un po 'di lavoro extra per verificare se c'è già il calzino corrispondente appeso da qualche parte e renderebbe la soluzione O(n^2)con coefficiente circa 1/2per un computer. Ma in questo caso il "fattore umano" è in realtà un vantaggio - di solito riesco a O(1)identificare molto rapidamente (quasi ) il calzino corrispondente se fosse già stato appeso (probabilmente è coinvolta una cache del cervello impercettibile) - lo considero una specie di "oracolo" limitato come in Oracle Machine ;-) In alcuni casi, gli umani hanno questi vantaggi rispetto alle macchine digitali ;-)

Quasi O(n)!

In questo modo, collegando il problema dell'abbinamento delle calze al problema dei panni appesi ottengo O(n)"spazio extra" gratuitamente, e ho una soluzione che è circa O(n)nel tempo, richiede solo un po 'più di lavoro rispetto ai semplici panni appesi e consente di accedere immediatamente a un paio completo di calzini anche in un brutto lunedì mattina ... ;-)


8

Spero di poter contribuire con qualcosa di nuovo a questo problema. Ho notato che tutte le risposte trascurano il fatto che ci sono due punti in cui è possibile eseguire la preelaborazione , senza rallentare le prestazioni generali del bucato.

Inoltre, non abbiamo bisogno di assumere un gran numero di calze, anche per le famiglie numerose. Le calze vengono estratte dal cassetto e vengono indossate, quindi vengono gettate in un posto (forse un bidone) dove rimangono prima di essere lavate. Anche se non chiamerei detto bin uno stack LIFO, direi che è sicuro supporre che

  1. la gente butta entrambe le calze all'incirca nella stessa area del cestino,
  2. il cestino non è randomizzato in nessun punto e quindi
  3. qualsiasi sottoinsieme prelevato dalla parte superiore di questo cestino generalmente contiene entrambi i calzini di una coppia.

Poiché tutte le lavatrici che conosco hanno dimensioni limitate (indipendentemente dal numero di calzini che devi lavare) e l'effettiva randomizzazione si verifica in lavatrice, indipendentemente dal numero di calzini che abbiamo, abbiamo sempre piccoli sottogruppi che contengono quasi single.

Le nostre due fasi di preelaborazione sono "mettere le calze sul filo del bucato" e "Prendere le calze dal filo del bucato", che dobbiamo fare per ottenere calzini non solo puliti ma anche asciutti. Come per le lavatrici, i fili per il bucato sono limitati e presumo che abbiamo l'intera parte della linea in cui mettiamo in vista le nostre calze.

Ecco l'algoritmo per put_socks_on_line ():

while (socks left in basket) {
 take_sock();
 if (cluster of similar socks is present) { 
   Add sock to cluster (if possible, next to the matching pair)
 } else {
  Hang it somewhere on the line, this is now a new cluster of similar-looking socks.      
  Leave enough space around this sock to add other socks later on 
 }
}

Non perdere tempo spostando i calzini o cercando la migliore corrispondenza, tutto ciò dovrebbe essere fatto in O (n), che avremmo anche bisogno di metterli sulla linea non ordinata. I calzini non sono ancora accoppiati, abbiamo solo diversi cluster di somiglianza sulla linea. È utile disporre di un numero limitato di calze qui, poiché ciò ci aiuta a creare cluster "buoni" (ad esempio, se nel set di calze ci sono solo calze nere, il raggruppamento per colore non sarebbe la strada da percorrere)

Ecco l'algoritmo per take_socks_from_line ():

while(socks left on line) {
 take_next_sock();
 if (matching pair visible on line or in basket) {
   Take it as well, pair 'em and put 'em away
 } else {
   put the sock in the basket
 }

Devo sottolineare che, al fine di migliorare la velocità dei passaggi rimanenti, è saggio non scegliere casualmente la calza successiva, ma prendere sequenzialmente calza dopo calza da ciascun cluster. Entrambe le fasi di preelaborazione non richiedono più tempo del semplice mettere le calze sulla linea o nel cestino, cosa che non dobbiamo fare in alcun modo, quindi questo dovrebbe migliorare notevolmente le prestazioni del bucato.

Dopodiché, è facile eseguire l'algoritmo di partizionamento hash. Di solito, circa il 75% delle calze è già accoppiato, lasciandomi con un piccolo sottoinsieme di calze, e questo sottoinsieme è già (un po ') raggruppato (non introduco molta entropia nel mio cestino dopo le fasi di preelaborazione). Un'altra cosa è che i cluster rimanenti tendono ad essere abbastanza piccoli da essere gestiti immediatamente, quindi è possibile estrarre un intero cluster dal cestino.

Ecco l'algoritmo per sort_remaining_clusters ():

while(clusters present in basket) {
  Take out the cluster and spread it
  Process it immediately
  Leave remaining socks where they are
}

Dopodiché, sono rimasti solo alcuni calzini. È qui che introduco nel sistema calze precedentemente non accoppiate ed elaboro le calze rimanenti senza alcun algoritmo speciale: le calze rimanenti sono pochissime e possono essere elaborate visivamente molto velocemente.

Per tutte le calze rimanenti, presumo che le loro controparti siano ancora non lavate e le metto via per la prossima iterazione. Se si registra una crescita di calzini non accoppiati nel tempo (una "perdita di calzino"), è necessario controllare il cestino: potrebbe essere randomizzato (ci sono gatti che dormono lì?)

So che questi algoritmi prendono molte ipotesi: un cestino che funge da una sorta di pila LIFO, una lavatrice normale limitata e una stendibiancheria limitata e normale - ma questo funziona ancora con un numero molto elevato di calze.

Informazioni sul parallelismo: finché lanci entrambe le calze nello stesso cestino, puoi facilmente parallelizzare tutti questi passaggi.


I calzini sono solo metafora per l'associazione di oggetti arbitrari in alcuni database.
Amit

1
Capito, non ho visto che sei l'autore. Se volevi una soluzione generica, avresti dovuto dirlo davvero. Ad ogni modo, non c'è nulla di sbagliato nel prendere in considerazione tutte le informazioni che hai, a meno che tu non debba trovare una soluzione generale: rinunciare alla riusabilità della soluzione potrebbe portare a prestazioni notevolmente migliori. In questo caso, è utile considerare il caso d'uso e il database disponibile nel suo insieme. Tuttavia, questa risposta speciale alla tua domanda speciale ha problemi con calzini simili, ad esempio calzini neri di diverse dimensioni, quindi non è applicabile in alcuni casi.
Philipp Flenker,

1
Inoltre, non hai ricevuto> 2k voti perché hai posto una domanda sull'associazione di oggetti arbitrari nel database. Hai specificamente limitato la domanda a causa della natura stessa dei calzini (che non puoi duplicare, al contrario dei dati), hai persino incoraggiato a utilizzare il fatto che puoi facilmente distinguere i calzini dai calzini del tuo coniuge. Se fai una domanda sui calzini, non aspettarti che le risposte riguardino i database ;-)
Philipp Flenker,

1
Ci sono alcuni presupposti: una normale lavatrice, una normale stendibiancheria e il fatto che si gettano entrambe le calze nel cestino contemporaneamente, il che significa che nella maggior parte dei casi entrambe le calze sono nella stessa macchina e il numero di le calze rimanenti da ordinare sono quindi piccole. Ma poiché hai davvero desiderato una risposta sulla memorizzazione di oggetti arbitrari nel database, è davvero utile discutere ulteriormente della mia soluzione?
Philipp Flenker,

1
Come ho detto, penso di aver affrontato tutto ciò che hai chiesto, ad eccezione del problema di distinzione tra elementi, a cui hanno risposto altre persone. Non sto cercando di essere un idiota qui, ma ho fatto molto sforzo in questa risposta qualche tempo fa, e sono leggermente deluso dal fatto che ora passi attraverso alcune delle risposte e affermi che non hanno risposto alla domanda originale . Perché non lasci solo l'intero thread da solo - è ancora una lettura interessante, oltre 2 anni dopo averlo chiesto?
Philipp Flenker,

8

Ho adottato semplici misure per ridurre i miei sforzi in un processo che richiede tempo O (1).

Riducendo i miei input a uno dei due tipi di calzini (calzini bianchi per la ricreazione, calzini neri per il lavoro), ho solo bisogno di determinare quale dei due calzini ho in mano. (Tecnicamente, dal momento che non vengono mai lavati insieme, ho ridotto il processo a O (0).)

È necessario un certo sforzo iniziale per trovare calze desiderabili e acquistare in quantità sufficiente da eliminare la necessità delle calze esistenti. Dato che l'avevo fatto prima del mio bisogno di calze nere, il mio sforzo era minimo, ma il chilometraggio poteva variare.

Un tale sforzo iniziale è stato visto molte volte in un codice molto popolare ed efficace. Gli esempi includono # DEFINE 'pi in diversi decimali (esistono altri esempi, ma quello è quello che viene in mente in questo momento).


7

Crea una tabella hash che verrà utilizzata per calze senza eguali, usando il modello come hash. Scorri i calzini uno per uno. Se la calza ha una corrispondenza del modello nella tabella hash, togli la calza dal tavolo e creane una coppia. Se la calza non ha una corrispondenza, inseriscila nel tavolo.


Come farlo non sul posto, come specificamente menzionato nella domanda?
Amit

7

Il problema di ordinare le tue n paia di calze è O (n) . Prima di gettarli nel cesto della biancheria , infilare quello sinistro a quello destro. Quando li togli, tagli il filo e metti ogni coppia nel tuo cassetto - 2 operazioni su n coppie, quindi O (n).

Ora la domanda successiva è semplicemente se fai il bucato e tua moglie fa la sua. Questo è un problema probabilmente in un dominio completamente diverso di problemi . :)


Questo non risponde alla domanda, in cui le calze sono solo una metafora.
Amit

La domanda era come accoppiare i calzini da un mucchio spaiato, non come evitare di abbinare.
Amit
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.