Un algoritmo che diffonde elementi simili in un elenco

3

Ho bisogno di un algoritmo che distribuisca gli stessi elementi in un elenco, in modo da massimizzare la distanza tra le occorrenze.

es. Ho una lista di 15 articoli:

{a,b,c,c,c,d,e,f,f,f,g,h,h,i,j}

L'algoritmo dovrebbe riordinarli in modo tale che tutti i duplicati vengano diffusi nel modo più uniforme possibile.

L'elenco menzionato dovrebbe risultare in qualcosa di simile:

{c,f,a,h,b,c,d,e,c,f,g,c,h,i,j,f}

Preferibilmente mi piacerebbe pseudo codice, e ancora meglio sarebbe TSQL (dato che è la piattaforma su cui deve essere eseguito). Ha bisogno di elaborare centinaia di questi elenchi in un colpo solo.

Ho anche testato un metodo proposto chiamato "Weighted shuffle", ma questo permetterà comunque che due degli stessi elementi nell'elenco vengano visualizzati uno accanto all'altro anche quando non è necessario.

    
posta Robert van Dijk 12.11.2014 - 14:57
fonte

2 risposte

2

Per prima cosa, assicurati che ci sia una soluzione in base alle tue esigenze (ciò significa che non c'è una singola lettera che si verifica più n / 2 volte, quando n è il numero totale di elementi).

Quindi ti suggerisco di provare il seguente

  • inizia con uno shuffle casuale o shuffle ponderato

  • in seguito, per ogni coppia rimanente di vicini simili, scegli uno degli elementi, scegli un altro oggetto scelto a caso tra quelli con vicini diversi e cambia posizione

  • ripeti l'ultimo passaggio fino a quando non vengono rimosse tutte le coppie.

Questo approccio si accerterà solo di non ottenere coppie vicine, ma non massimizza le possibili distanze tra lettere simili. Se vuoi raggiungere il secondo (che non è chiaro dalla tua domanda), ti suggerisco di introdurre una funzione punteggio nel tuo elenco, ad esempio in questo modo:

 Score(list) := Sum(1/(abs(a-b)-0.999))
                a,b

dove la somma supera tutte le coppie (a,b) di posizioni di lettere uguali. Il "-0.999" nel denominatore si assicura che l'intera espressione diventi molto grande quando ci sono 2 vicini uguali. Ora puoi applicare swap casuali alla tua lista e cercare di minimizzare la funzione di punteggio, ad esempio per hill climbing o ricottura simulata .

    
risposta data 13.11.2014 - 11:53
fonte
1

Se sei solo preoccupato di dividere le righe simili e non preoccuparti di assicurarti che siano a intervalli regolari, puoi usare qualcosa come la seguente:

Determina un peso per ogni gruppo di lettere, quindi utilizza la funzione ROW_NUMBER per calcolare una distribuzione di ordinamenti. Modificando la ponderazione e / o l'ordinamento nella selezione finale, è possibile ottenere i risultati necessari.

CREATE TABLE #items (letter char(1))
INSERT INTO #items VALUES ('a')
INSERT INTO #items VALUES ('b')
INSERT INTO #items VALUES ('c')
INSERT INTO #items VALUES ('c')
INSERT INTO #items VALUES ('c')
INSERT INTO #items VALUES ('d')
INSERT INTO #items VALUES ('e')
INSERT INTO #items VALUES ('f')
INSERT INTO #items VALUES ('f')
INSERT INTO #items VALUES ('f')
INSERT INTO #items VALUES ('g')
INSERT INTO #items VALUES ('h')
INSERT INTO #items VALUES ('h')
INSERT INTO #items VALUES ('i')
INSERT INTO #items VALUES ('j')
ALTER TABLE #items ADD weight numeric(4,2) 

--Add weight for each letter
DECLARE @itemcount numeric(4,2) = (SELECT COUNT(*) FROM #items)
UPDATE #items set weight = @itemcount / (SELECT COUNT(*) FROM #items i WHERE letter = #items.letter)

--Sort items by weight, using row_number to space out letter groups
;WITH cteNumbered AS (SELECT letter, weight, ROW_NUMBER() OVER (PARTITION BY letter ORDER BY letter) as rownum FROM #items)
SELECT letter from cteNumbered ORDER BY rownum * weight, weight desc, letter
    
risposta data 22.11.2014 - 08:03
fonte

Leggi altre domande sui tag