Contatta Lovato Damiano via mail
|  HOME  |  CURRICULUM  |  PROGETTI  |  GUESTBOOK  |          

ELEMENTI DI PROGRAMMAZIONE PER IL CALCOLO COMBINATORIO


Permutazioni senza ripetizioni (Fattoriale):
Funzione per il calcolo del fattoriale utilizzata successivamente per effettuare le operazioni di calcolo combinatorio; la funzione fattoriale fornisce il numero di permutazioni che è possibile ottenere da [n] elementi; notare inoltre che la permutazione è un caso particolare di disposizione semplice senza ripetizione avente il numero di elementi di raggruppamento uguale al numero totale di elementi disponibili:

VBA : CodiceCalcoloCombinatorio001
01 : Function Fattoriale(ByVal n As Long) As Long
02 : Dim i As Long
03 : Dim Risultato As Long
04 : Risultato = 1
05 : For i = 2 To n
06 :   Risultato = Risultato * i
07 : Next i
08 : Fattoriale = Risultato
09 : End Function


Per il calcolo delle permutazioni senza ripetizione un buon algoritmo sembrerebbe essere lo "Steinhaus Johnson Trotter algorithm"; qui di seguito l'ho implementato in VBA :

VBA : CodiceCalcoloCombinatorio007
01 : Private Sub Genera_Click()
02 :   Call GeneraPermutazioni("lovaz")
03 : End Sub
04 : ' XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
05 : Function GeneraPermutazioni(ByVal Testo As String)
06 : ' Dichiarazione delle variabili
07 : Dim TempoInizio As Double
08 : Dim TempoFine As Double
09 : Dim MessaggioErrore As String
10 : Dim NomeFile As String
11 : Dim StringaPermutazione As String
12 : Dim StringaScambi As String
13 : Dim StringaDirezioni As String
14 : Dim Iterazioni As Long
15 : Dim MaxIterazioni As Long
16 : Dim NumElementi As Integer
17 : Dim Contatore As Long
18 : Dim i As Integer
19 : Dim j As Integer
20 : Dim Temp As Variant
21 : Dim RicercaPermutazione As Boolean
22 : Dim Posizione As Integer
23 : Dim Valore As Integer
24 : Dim Maggiore As Boolean
25 : Dim Mobile As Boolean
26 : Dim PosMag As Integer 'Posizione dell' elemento maggiore
27 : Dim LimiteMag As Integer 'Limite per la selezione del maggiore
28 : Dim CambiaDirezione As Boolean
29 : Dim arrayElementi() As String
30 : Dim ArrayScambi() As Integer
31 : Dim ArrayDirezioni() As Integer
32 : ' Settaggio delle variabili e degli array
33 : TempoInizio = Timer
34 : NomeFile = "LovazTestPermutazioni.txt"
35 : RicercaPermutazione = True
36 : Iterazioni = 0
37 : MaxIterazioni = 10000000
38 : NumElementi = Len(Testo)
39 : ReDim arrayElementi(1 To Len(Testo))
40 : For Contatore = 1 To NumElementi
41 :   arrayElementi(Contatore) = Mid(Testo, Contatore, 1)
42 : Next Contatore
43 : ReDim ArrayScambi(1 To Len(Testo))
44 : For Contatore = 1 To NumElementi
45 :   ArrayScambi(Contatore) = Contatore
46 : Next Contatore
47 : ReDim ArrayDirezioni(1 To Len(Testo))
48 : For Contatore = 1 To NumElementi
49 :   ArrayDirezioni(Contatore) = -1
50 : Next Contatore
51 : ' INIZIA LA GENERAZIONE DELLE PERMUTAZIONI
52 : ' Apri il file in scrittura per l'output dei dati
53 : Open NomeFile For Output As #1
54 : Print #1, "Lovaz - Generatore permutazioni"
55 : ' Inizia il ciclo di elaborazione e scrittura delle permutazioni
56 : Do While RicercaPermutazione
57 :   ' Libera il testo contenuto nelle stringhe di output
58 :   StringaPermutazione = ""
59 :   StringaScambi = ""
60 :   StringaDirezioni = ""
61 :   ' Genera le stringhe di output
62 :   For Contatore = 1 To NumElementi
63 :     StringaPermutazione = StringaPermutazione & arrayElementi(Contatore)
64 :     StringaScambi = StringaScambi & ArrayScambi(Contatore)
65 :     If ArrayDirezioni(Contatore) = -1 Then
66 :       StringaDirezioni = StringaDirezioni & "-"
67 :     Else
68 :       StringaDirezioni = StringaDirezioni & "+"
69 :     End If
70 :   Next Contatore
71 :   ' Scrivi sul file di testo le stringhe generate
72 :   Print #1, StringaPermutazione & "|" & StringaScambi & "|" & StringaDirezioni
73 :   ' Inizia il ciclo di ricerca del valore mobile più grande e rileva la sua posizione
74 :   LimiteMag = UBound(arrayElementi) + 1
75 :   Posizione = 0
76 :   Maggiore = False
77 :   Mobile = False
78 :   Do Until Maggiore = True And Mobile = True
79 :     Valore = 0
80 :     ' Verifca in tutto l'array qual'è il valore maggiore considerando eventuali elementi bloccati
81 :     For i = LBound(arrayElementi) To UBound(arrayElementi)
82 :       If (ArrayScambi(i) > Valore And ArrayScambi(i) < LimiteMag) Then
83 :         Maggiore = True
84 :         Valore = ArrayScambi(i)
85 :         PosMag = i
86 :       End If
87 :     Next i
88 :     ' Verifica che l'elemento trovato non sia arrivato ai margini e quindi non possa essere spostato.
89 :     If (PosMag + ArrayDirezioni(PosMag) < LBound(arrayElementi) Or PosMag + ArrayDirezioni(PosMag) > UBound(arrayElementi)) Then
90 :       Mobile = False
91 :       LimiteMag = ArrayScambi(PosMag)
92 :       CambiaDirezione = True
93 :       'MsgBox "Il valore trovato ha direzione tale da puntare all' esterno del margine SX o DX; occorre cercare un nuovo numero inferiore a questo"
94 :     Else
95 :       ' Verifica che l'elemento adiacente a quello da spostare non sia maggiore
96 :       If (ArrayScambi(PosMag + ArrayDirezioni(PosMag)) > ArrayScambi(PosMag)) Then
97 :         Mobile = False
98 :         LimiteMag = ArrayScambi(PosMag)
99 :         'MsgBox "Il valore maggiore non può essere spostato in questa direzione perchè ha un numero ancora più grande; occorre cercare il maggiore escluso questo"
100 :       Else
101 :         Mobile = True
102 :         Posizione = PosMag
103 :       End If
104 :     End If
105 :     ' Se è stato impostato come limite maggiore 1 significa che non si riesce più a trovare un numero mobile
106 :     If LimiteMag = 1 Then Exit Do
107 :   Loop
108 :   ' Effettua lo scambio nel caso in cui sia stata trovata una posizione valida
109 :   If (Posizione <> 0) Then
110 :     i = Posizione
111 :     j = i + ArrayDirezioni(i)
112 :     ' Cambia la direzione a tutti gli elementi maggiori all'ultimo elemento mobile trovato
113 :     If CambiaDirezione = True Then
114 :       For Contatore = LBound(arrayElementi) To UBound(arrayElementi)
115 :         If (ArrayScambi(Contatore) > ArrayScambi(Posizione)) Then
116 :           ArrayDirezioni(Contatore) = ArrayDirezioni(Contatore) * -1
117 :         End If
118 :       Next Contatore
119 :       CambiaDirezione = False
120 :     End If
121 :     ' Aggiorna array degli elementi
122 :     Temp = arrayElementi(i)
123 :     arrayElementi(i) = arrayElementi(j)
124 :     arrayElementi(j) = Temp
125 :     ' Aggiorna array degli scambi
126 :     Temp = ArrayScambi(i)
127 :     ArrayScambi(i) = ArrayScambi(j)
128 :     ArrayScambi(j) = Temp
129 :     ' Aggiorna array delle direzioni
130 :     Temp = ArrayDirezioni(i)
131 :     ArrayDirezioni(i) = ArrayDirezioni(j)
132 :     ArrayDirezioni(j) = Temp
133 :   Else
134 :     RicercaPermutazione = False
135 :   End If
136 :   ' Verifica del limite di iterazioni per fermare eventuali elaborazioni
137 :   ' troppo pesanti o bloccare cicli infiniti
138 :   Iterazioni = Iterazioni + 1
139 :   If (Iterazioni > MaxIterazioni) Then
140 :     MessaggioErrore = "Superato limite massimo iterazioni (" & Iterazioni & ")"
141 :     RicercaPermutazione = False
142 :   End If
143 : Loop
144 : Close #1 'Chiusura File
145 : TempoFine = Timer
146 : If Not (MessaggioErrore = "") Then MsgBox MessaggioErrore
147 : MsgBox "Ciclo di elaborazione concluso in: " & TempoFine - TempoInizio & " secondi" & vbCrLf & "Iterazioni eseguite: " & Iterazioni
148 : End Function


Dismutazioni:
Calcolo delle permutazioni di [n] elementi in modo tale che gli elementi non compaiano mai nella posizione originaria:

VBA : CodiceCalcoloCombinatorio004
01 : Function Dismutazioni(ByVal n As Long) As Long
02 : Dim i As Long
03 : Dim Risultato As Long
04 : Risultato = 0
05 : For i = 0 To n
06 :   Risultato = Risultato + (-1) ^ i * Fattoriale(n) / Fattoriale(i)
07 : Next i
08 : Dismutazioni = Risultato
09 : End Function


Disposizioni senza ripetizione:
Calcola i raggruppamenti di [k] elementi scelti dall' insieme di [n] elementi tale che ogni raggruppamento differisca dagli altri o per gli elementi presenti oppure per l'ordinamento degli elementi considerando che ogni elemento può comparire solamente una volta (motivo per cui il numero [k] di elementi del raggruppamento non può essere maggiore degli elementi disponibili nell' insieme di [n] elementi):

VBA : CodiceCalcoloCombinatorio002
01 : Function DisposizioniSenzaRipetizione(ByVal n As Long, ByVal k As Long) As Long
02 : Dim Risultato As Long
03 : If k <= n Then
04 :   Risultato = Fattoriale(n) / Fattoriale(n - k)
05 : Else
06 :   Risultato = -1 'Errore il numero di posizioni è maggiore del numero di elementi a disposizione
07 : End If
08 : DisposizioniSenzaRipetizione = Risultato


Disposizioni con ripetizione:
Calcola i raggruppamenti di [k] elementi scelti dall' insieme di [n] elementi tale che ogni raggruppamento differisca dagli altri o per gli elementi presenti oppure per l'ordinamento degli elementi considerando che ogni elemento può comparire più volte:

VBA : CodiceCalcoloCombinatorio003
01 : Function DisposizioniConRipetizione(ByVal n As Long, ByVal k As Long) As Long
02 : Dim Risultato As Long
03 : Risultato = n ^ k
04 : DisposizioniConRipetizione = Risultato
05 : End Function


Combinazioni senza ripetizione:
Calcola quanti raggruppamenti di [k] elementi è possibile generare da un insieme di [n] elementi tenendo conto che non ha importanza l'ordinamento degli elementi all' interno del raggruppamento e ogni raggruppamento non può avere lo stesso elemento ripetuto (NB: risulta uguale al rapporto tra le disposizioni senza ripetizione e le permutazioni ottenibili in base al numero di elementi del raggruppamento):

VBA : CodiceCalcoloCombinatorio005
01 : Function CombinazioniSenzaRipetizione(ByVal n As Long, ByVal k As Long) As Long
02 : Dim Risultato As Long
03 : If k <= n Then
04 :   Risultato = Fattoriale(n) / (Fattoriale(k) * Fattoriale(n - k))
05 : Else
06 :   Risultato = -1 'Errore la classe è maggiore del numero di elementi a disposizione
07 : End If
08 : CombinazioniSenzaRipetizione = Risultato
09 : End Function


Combinazioni con ripetizione:
Calcola quanti raggruppamenti di [k] elementi è possibile generare da un insieme di [n] elementi tenendo conto che non ha importanza l'ordinamento degli elementi all' interno del raggruppamento e ogni raggruppamento può avere lo stesso elemento ripetuto:

VBA : CodiceCalcoloCombinatorio006
01 : Function CombinazioniConRipetizione(ByVal n As Long, ByVal k As Long) As Long
02 : Dim Risultato As Long
03 : Risultato = Fattoriale(n + k - 1) / (Fattoriale(k) * Fattoriale(n - 1))
04 : CombinazioniConRipetizione = Risultato
05 : End Function