Belirli bir rasgele sayı üreteci kullanarak 1-100 yazdırmak için en verimli algoritma


11

Bize RandNum501–50 aralığında eşit olarak rasgele bir tamsayı üreten rastgele bir sayı üreteci verilir . 1'den 100'e kadar tüm tamsayıları rastgele bir sırayla oluşturmak ve yazdırmak için sadece bu rastgele sayı üretecini kullanabiliriz. Her sayı tam olarak bir kez gelmeli ve herhangi bir yerde meydana gelen herhangi bir sayının olasılığı eşit olmalıdır.

Bunun için en verimli algoritma nedir?


1
Görülen sayıları kaydetmek için bir dizi / veya bit vektörü ve görülen benzersiz sayıların sayısını kaydetmek için bir sayaç kullanın.
Dave Clarke

@DaveClarke Bununla nasıl 50'den büyük bir sayı oluşturabilirim? 1 kereden fazla kullanırsam, bunları kullanarak nasıl 1 üreteceğim?
Raj Wadhwa

1
Elbette zorluk, tüm yerlerin eşit olasılıkla gerçekleşmesini sağlamaktır. Kullanabilirsin RandNum100 = (RandNum50() * 2) - (RandNum50 > 25) ? 0 : 1).
Dave Clarke

2
@DaveClarke: Yani yinelenen ret örneklemesi mi öneriyorsunuz? Bu sadece beklentiyle sona erecekti.
Raphael

Sadece bir ipucu veriyordum.
Dave Clarke

Yanıtlar:


3

Düşündüm (bu yüzden yanlış olabilir :-) Fisher-Yates shuffle kullanan bu çözüm . İle homojen dağılımını sağlamak amacıyla iyi bir yaklaşımla Bir değer üretmek için bu hileyi kullanabilirsiniz her işleminde (aşağıdaki DÜZENLEME bölümüne bakınız) arasında 0 ve k - 1 :Ö(N-2)krand0k-1

 // return a random number in [0..k-1] with uniform distribution
 // using a uniform random generator in [1..50]
 funtion krand(k) {    
   sum = 0
   for i = 1 to k do sum = sum + RandNum50() - 1
   krand = sum mod k
 }

Fisher-Yates algoritması:

arr : array[0..99]
for i = 0  to 99 do arr[i] = i+1; // store 1..100 in the array
for i = 99 downto 1 {
  r = krand(i+1)  // random value in [0..i]
  exchange the values of arr[i] and arr[r]
}
for i = 0 to 99 do print arr[i]

DÜZENLE:

Erick tarafından krandbelirtildiği gibi, yukarıdaki fonksiyon gerçekten tekdüze bir dağılım getirmez. Daha iyi (keyfi olarak daha iyi) ve daha hızlı bir yaklaşım elde etmek için kullanılabilecek başka yöntemler de vardır; ancak (en bilgi) gerçekten eşit bir dağılım elde etmek için tek yol kullanmaktır ret örnekleme çekme: rasgele bit sayısı ise r elde az olan K dönüş, aksi takdirde elde başka bir rasgele sayı; olası bir uygulama:m=günlük2(k)rk

function trulyrand(k) {
    if (k <= 1) return 0
    while (true) { // ... if you're really unlucky ...
      m = ceil(log_2 (k) ) // calculate m such that k < 2^m
      r = 0  // will hold the random value
      while (m >= 0) {  // ... will add m bits        
        if ( rand50() > 25 ) then b = 1 else b = 0   // random bit
        r = r * 2 + b  // shift and add the random bit
        m = m - 1
      }      
      if (r < k) then return r  // we have 0<=r<2^m ; accept it, if r < k
    }
}

1
Bağlandığınız wikipedia sayfası bir varyantı olduğunu belirtir . Ö(n)
Dave Clarke

1
Bence "shuffle" burada anahtar kelime.
Raphael

4
Krand (k) 'deki hile, iyi bir yaklaşım olmasına rağmen gerçekten tekdüze bir dağılım üretmez: k = 3 için bile bu,% 33.333328'lik bir çıkış şansı verir. Burada k'ye kadar toplamanın bir nedeni var mı? ? Sadece bir yaklaşım istiyorsak daha küçük bir sınırın yeterli olacağını düşünürüm.
Erick Wong

1
@ErickWong: haklısın; Gerçek üniforma dağılımına ancak sabit zamanda bitmesi garanti edilmeyen ret örnekleme yöntemi kullanılarak ulaşılabileceğini düşünüyorum. Başka bir yaklaşım şeması da var (istenen herhangi bir yaklaşıma ulaşmaya izin veriyor), önerdiğim aklıma ilk gelen.
Vor

2
@ ex0du5: Bunu biliyorum, ancak [1..100] 'de sadece tek tip rastgele bir jeneratör kullanarak sayıların düzgün rasgele permütasyonunu [1..100] nasıl üretiyorsunuz? Bildiğim tek alternatif yöntem şudur: 1. adım ) 1..100'de rastgele bir değeri seçin ; adım2) r zaten seçilmişse, atın ve adım 1'e gidin; adım 3) baskı r ; adim 4) tüm 100 sayıları bastırmadıysak adim 1'e geçin. Ancak bu yöntem, reddetmeyi daha önce seçilmiş öğelere kaydırır. r1..100rr
Vor

4

Diğer kişiler belirsiz sayıda sapma almayı içeren yaklaşık çözümler ve çözümler sunduğundan, yalnızca sınırlı sayıda RandNum50()arama gerektirecek garantili böyle bir algoritmanın olmadığını kanıtlamaya ne dersiniz ?

Diğerlerinin de belirttiği gibi, 1-100 arasındaki sayıları rastgele sırada yazdırmak, bu sayıların rastgele permütasyonunu yazdırmaya eşdeğerdir; 100 var! Bu permütasyonların ve dolayısıyla herhangi bir belirli permütasyonun olasılıkla çıktısı alınmalıdır .1100!

kRandNum50kkRandNum50kkRandNum50(r1,r2,...,rk)150kc50kc1100!100!50kk100!50k


2

ngünlükn+Ö(1)

if ( rand50() > 25 ) then b = 1 else b = 0   // random bit

1n!123n

Bu yazıda önerildiği gibi bir üniformayı nasıl rastgele bir bitten üreteceğinizi bilmiyorsanız, üniformanın doğrudan bu şekilde (Vor'un "gerçeküstü" sine eşdeğer, ancak daha hızlı) da üretebilirsiniz:

P = (RandNum50()-1) + (RandNum50()-1)*50^1 + (RandNum50()-1)*50^2 + ...

P50PS=Pşıknn=100!P>n


1

Bunun ne kadar tekdüze (ya da değil) olduğunu doğrulamak için analiz yapmadım ve gerçek bir shuffle olacak şekilde ayarlanabilir, ancak ith indeksinin başlangıç ​​dizisinden = i + 1, (k + RandNum50() + RandNum50() - 1) mod (100 - k)endeksi, kaldırma, k= 0..99?

Bu RandNum50() + RandNum50()dağılımdaki zirveyi eşit olarak "iter" .

0 endeksi (1) ilk seçimden elde edilemediğinden ve hızlı bir şekilde 0 üreten alternatif 1..50 + 1..50 ayarlaması göremediğimden, bunun belirttiğim gibi oldukça doğru olmadığından eminim. ..99.

Güncelleme

Belirttiğim sorunu düzeltmek için RandNum100, ilk kofseti rastgele başlatmak için soru yorumlarında belirtildiği gibi etkili bir şekilde kullandım .

Bu, önde önemli bir dalga ile bir dağılım üretir.

1 ile ilerlemek yerine RandNum50önce bunu artırmak için başka bir tane kullandım k. Bu benim için yeterince rastgele bir sonuç üretir, ancak yine de "gerçekten" rastgele değildir, çünkü K'yi 2'ye değiştirirseniz kolayca görülebilir.

Hatta herhangi bir K için yiyecek ve içecek VB.NET kodunu test Aslında, O (K), 6K + 2 olduğunu unutmayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.