Recentemente ho iniziato a imparare Prolog e ho avuto l'incarico di scrivere un predicato list(N, L)
che genera elenchi di L tale che:Genera tutte le permutazioni della lista [1, 1, 2, 2, ..., n, n] dove il numero di elementi tra ogni coppia è pari in Prolog
- L ha 2N lunghezza,
- ogni numero compreso tra 1 e N avviene esattamente il doppio a L,
- fra ciascuna coppia dello stesso elemento è un ancora numero di altri elementi,
- le prime occorrenze di ogni numero sono in ordine crescente ER.
L'autore afferma che ci sono N! tali elenchi.
Ad esempio, per N = 3 Tutte le soluzioni sono:
?- list(3, L).
L = [1, 1, 2, 2, 3, 3] ;
L = [1, 1, 2, 3, 3, 2] ;
L = [1, 2, 2, 1, 3, 3] ;
L = [1, 2, 2, 3, 3, 1] ;
L = [1, 2, 3, 3, 2, 1] ;
L = [1, 2, 3, 1, 2, 3] ;
false.
mia soluzione attuale si presenta come:
even_distance(H, [H | _]) :-
!.
even_distance(V, [_, _ | T]) :-
even_distance(V, T).
list(N, [], _, Length, _, _) :-
Length =:= 2*N,
!.
list(N, [New | L], Max, Length, Used, Duplicates) :-
select(New, Duplicates, NewDuplicates),
even_distance(New, Used),
NewLength is Length + 1,
list(N, L, Max, NewLength, [New | Used], NewDuplicates).
list(N, [New | L], Max, Length, Used, Duplicates) :-
Max < N,
New is Max + 1,
NewLength is Length + 1,
list(N, L, New, NewLength, [New | Used], [New | Duplicates]).
list(N, L) :-
list(N, L, 0, 0, [], []).
lo fa due cose:
- se la corrente massima è meno di N, aggiungi quel numero alla lista, mettilo nell'elenco dei duplicati e aggiorna il massimo;
- selezionare alcuni duplicati, controllare se è presente un numero pari di elementi tra esso e il numero già presente nell'elenco (cioè quel numero è in posizione dispari), quindi aggiungerlo all'elenco e rimuoverlo dai duplicati.
Funziona, ma è lento e non sembra molto bello.
L'autore di questo esercizio mostra che per N < 12, la sua soluzione genera un singolo elenco con inferenze medie di ~ 11 (utilizzando time/1
e dividendo il risultato per N!). Con la mia soluzione cresce a ~ 60.
Ho due domande:
- come migliorare questo algoritmo?
- Questo problema può essere generalizzato ad altri noti? Conosco problemi simili basati sul multiset
[1, 1, 2, 2, ..., n, n]
(ad esempio l'accoppiamento con Langford), ma non sono riuscito a trovare qualcosa di simile.
Sto chiedendo perché il problema originale riguarda enumerare le intersezioni in una curva chiusa autointersecante. Si disegna tale curva, si seleziona un punto e una direzione e si segue la curva, elencando ciascuna intersezione quando viene raggiunto per la prima volta e ripetendo il numero nella seconda riunione: example (con la risposta [1, 2, 3, 4, 5, 3, 6, 7, 8, 1, 9, 5, 4, 6, 7, 9, 2, 8]
).
L'autore afferma che ciascuna di tali curve soddisfa il predicato list
, ma non tutte le liste corrispondono a una curva.
s (X) per astuzia! – repeat