Bilgisayar Programlama Sanatı Cilt 4: Fascicle 3'te , kendi durumunuza anlattığımdan daha iyi uyan bir ton var.
Gri Kodlar
Karşılaşacağınız bir konu elbette bellek ve oldukça hızlı bir şekilde, setinizde 20 elementle ilgili sorunlarınız olacak - 20 C 3 = 1140. Ve seti tekrarlamak istiyorsanız, modifiye edilmiş bir gri kullanmak en iyisidir kod algoritması sayesinde hepsini bellekte tutmuyorsunuz. Bunlar bir öncekinden bir sonraki kombinasyonu oluşturur ve tekrarlardan kaçınır. Farklı kullanımlar için bunların birçoğu vardır. Ardışık kombinasyonlar arasındaki farkları en üst düzeye çıkarmak istiyor muyuz? küçültmek? ve benzeri.
Gri kodları açıklayan bazı orijinal makaleler:
- Bazı Hamilton Yolları ve Minimal Değişim Algoritması
- Bitişik Kavşak Kombinasyonu Üretimi Algoritması
İşte konuyu kapsayan diğer bazı makaleler:
- Eades'in Etkili Bir Uygulaması, Hickey, Komşu Değişen Kombinasyon Üretimi Algoritmasını Oku (PDF, Pascal'da kod ile)
- Kombinasyon Jeneratörleri
- Kombinatoryal Gri Kodların Araştırılması (PostScript)
- Gri Kodlar için Bir Algoritma
Chase's Twiddle (algoritma)
Phillip J Chase, `` Algoritma 382: N Nesnelerinden M'nin Kombinasyonları '' (1970)
C'deki algoritma ...
Sözlükbilimsel Sıradaki Kombinasyonlar Dizini (Buckles Algorithm 515)
Ayrıca bir kombinasyona dizinine göre (sözlük sırasına göre) başvurabilirsiniz. Endekse dayalı olarak endeksin sağdan sola bir miktar değişiklik olması gerektiğini fark ederek, bir kombinasyonu kurtarması gereken bir şey oluşturabiliriz.
Yani, bir küme {1,2,3,4,5,6} ... var ve üç element istiyoruz. Diyelim ki {1,2,3} elementler arasındaki farkın bir, düzenli ve minimum olduğunu söyleyebiliriz. {1,2,4} bir değişikliğe sahiptir ve sözlükbilimsel olarak 2 numaradır. Dolayısıyla, son yerdeki 'değişikliklerin' sayısı sözlükbilimsel düzende bir değişiklikten sorumludur. {1.3,4} değerindeki bir değişikliğe sahip ikinci sırada bir değişiklik olur, ancak ikinci sırada olduğundan daha fazla değişiklik olur (orijinal kümedeki öğe sayısıyla orantılı).
Anlattığım yöntem, göründüğü gibi, setten indekse, tersine yapmamız gerekiyor - ki bu çok daha karmaşık. Bu nasıl Toka sorunu çözer. Onları hesaplamak için küçük değişiklikler yaparak biraz C yazdım - seti temsil etmek için bir sayı aralığı yerine kümelerin dizinini kullandım, bu yüzden her zaman 0 ... n'den çalışıyoruz. Not:
- Kombinasyonlar sırasız olduğundan, {1,3,2} = {1,2,3} - sözlükbilimsel olmalarını isteriz.
- Bu yöntem, ilk farkın kümesini başlatmak için örtük 0 değerine sahiptir.
Sözlükbilimsel Sıradaki Kombinasyonlar Dizini (McCaffrey)
Orada başka bir yolu da kavram kavramak ve programa daha kolaydır, ancak Tokalar optimizasyonlar olmadan var. Neyse ki, aynı zamanda yinelenen kombinasyonlar üretmez:
Maksimize eden set , nerede .
Örnek olarak: 27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Yani, dört şeyin 27. sözlükbilimsel kombinasyonu şöyledir: {1,2,5,6}, bakmak istediğiniz setin dizinleri. Aşağıdaki örnek (OCaml), choose
okuyucuya bırakılan işlev gerektirir :
(* 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)
Küçük ve basit kombinasyonlar yineleyicisi
Didaktik amaçlar için aşağıdaki iki algoritma sağlanmıştır. Bir yineleyici ve (daha genel) klasör genel kombinasyonları uygularlar. O ( n C k ) karmaşıklığına sahip olabildiğince hızlıdırlar . Bellek tüketimi buna bağlıdır k
.
Her kombinasyon için kullanıcı tarafından sağlanan bir işlevi çağıran yineleyici ile başlayacağız
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
Daha genel bir sürüm, başlangıç durumundan başlayarak durum değişkeni ile birlikte kullanıcı tarafından sağlanan işlevi çağıracaktır. Durumu farklı durumlar arasında geçirmemiz gerektiğinden, for-loop'u kullanmıyoruz, bunun yerine özyineleme kullanıyoruz,
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