Seni Pemrograman Komputer Volume 4: Fascicle 3 memiliki banyak ini yang mungkin cocok dengan situasi khusus Anda lebih baik daripada cara saya menggambarkan.
Kode Abu-abu
Masalah yang akan Anda temui tentu saja adalah memori dan cukup cepat, Anda akan memiliki masalah dengan 20 elemen di set Anda - 20 C 3 = 1140. Dan jika Anda ingin beralih di set, yang terbaik adalah menggunakan abu-abu yang dimodifikasi algoritma kode sehingga Anda tidak menyimpan semuanya dalam memori. Ini menghasilkan kombinasi berikutnya dari sebelumnya dan menghindari pengulangan. Ada banyak dari ini untuk kegunaan yang berbeda. Apakah kita ingin memaksimalkan perbedaan antara kombinasi yang berurutan? memperkecil? dan lain-lain.
Beberapa makalah asli yang menggambarkan kode abu-abu:
- Beberapa Jalur Hamilton dan Algoritma Perubahan Minimal
- Algoritma Generasi Kombinasi Pertukaran Bersebelahan
Berikut adalah beberapa makalah lain yang membahas topik ini:
- Implementasi Efisien dari Eades, Cupang, Baca Algoritma Generasi Kombinasi Interchange Berdampingan (PDF, dengan kode dalam Pascal)
- Generator Kombinasi
- Survei Kode Kelabu Kombinatorial (PostScript)
- Algoritma untuk Kode Gray
Chase's Twiddle (algoritme)
Phillip J Chase, ` Algoritma 382: Kombinasi M out of N Objects '(1970)
Algoritme dalam C ...
Indeks Kombinasi dalam Urutan Leksikografis (Algoritma Buckles 515)
Anda juga dapat mereferensikan kombinasi berdasarkan indeksnya (dalam urutan leksikografis). Menyadari bahwa indeks harus berupa sejumlah perubahan dari kanan ke kiri berdasarkan indeks, kita dapat membuat sesuatu yang harus memulihkan kombinasi.
Jadi, kami memiliki satu set {1,2,3,4,5,6} ... dan kami ingin tiga elemen. Katakanlah {1,2,3} kita dapat mengatakan bahwa perbedaan antara elemen adalah satu dan dalam urutan dan minimal. {1,2,4} memiliki satu perubahan dan secara leksikografis nomor 2. Jadi jumlah 'perubahan' di tempat terakhir menyumbang satu perubahan dalam pemesanan leksikografis. Tempat kedua, dengan satu perubahan {1,3,4} memiliki satu perubahan tetapi menyumbang lebih banyak perubahan karena berada di tempat kedua (sebanding dengan jumlah elemen dalam set asli).
Metode yang saya jelaskan adalah dekonstruksi, seperti yang terlihat, dari set ke indeks, kita perlu melakukan sebaliknya - yang jauh lebih rumit. Inilah cara Buckles memecahkan masalah. Saya menulis beberapa C untuk menghitungnya , dengan perubahan kecil - Saya menggunakan indeks set daripada rentang angka untuk mewakili set, jadi kami selalu bekerja dari 0 ... n. catatan:
- Karena kombinasi tidak berurutan, {1,3,2} = {1,2,3} --kami memesannya harus leksikografis.
- Metode ini memiliki 0 implisit untuk memulai set untuk perbedaan pertama.
Indeks Kombinasi dalam Urutan Leksikografis (McCaffrey)
Ada cara lain : konsepnya lebih mudah dipahami dan diprogram tetapi tanpa optimalisasi Buckles. Untungnya, itu juga tidak menghasilkan kombinasi duplikat:
Himpunan yang memaksimalkan , di mana .
Untuk contoh: 27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Jadi, kombinasi leksikografis ke-27 dari empat hal adalah: {1,2,5,6}, itu adalah indeks dari set apa pun yang ingin Anda lihat. Contoh di bawah ini (OCaml), memerlukan choose
fungsi, diserahkan kepada pembaca:
(* this will find the [x] combination of a [set] list when taking [k] elements *)
let combination_maccaffery set k x =
(* maximize function -- maximize a that is aCb *)
(* return largest c where c < i and choose(c,i) <= z *)
let rec maximize a b x =
if (choose a b ) <= x then a else maximize (a-1) b x
in
let rec iterate n x i = match i with
| 0 -> []
| i ->
let max = maximize n i x in
max :: iterate n (x - (choose max i)) (i-1)
in
if x < 0 then failwith "errors" else
let idxs = iterate (List.length set) x k in
List.map (List.nth set) (List.sort (-) idxs)
Iterator kombinasi kecil dan sederhana
Dua algoritma berikut disediakan untuk tujuan didaktik. Mereka menerapkan iterator dan (secara keseluruhan) folder kombinasi keseluruhan. Mereka adalah secepat mungkin, memiliki kompleksitas O ( n C k ). Konsumsi memori terikat oleh k
.
Kami akan mulai dengan iterator, yang akan memanggil fungsi yang disediakan pengguna untuk setiap kombinasi
let iter_combs n k f =
let rec iter v s j =
if j = k then f v
else for i = s to n - 1 do iter (i::v) (i+1) (j+1) done in
iter [] 0 0
Versi yang lebih umum akan memanggil fungsi yang disediakan pengguna bersama dengan variabel status, mulai dari status awal. Karena kita harus melewati status di antara berbagai status, kita tidak akan menggunakan for-loop, tetapi sebaliknya, gunakan rekursi,
let fold_combs n k f x =
let rec loop i s c x =
if i < n then
loop (i+1) s c @@
let c = i::c and s = s + 1 and i = i + 1 in
if s < k then loop i s c x else f c x
else x in
loop 0 0 [] x