Rastgele azalmayan bir dizi örneği


20

Giriş: Kodunuz için uygun herhangi bir biçimde verilen iki n ve k tamsayısı

Çıktı Her biri 1 ila n aralığında olan rastgele azalmayan k tam sayı dizisi. Numune, 1 ila n aralığında tamsayılara sahip k azalmayan tüm k azalmayan dizilerinden eşit olarak seçilmelidir.

Çıktı, uygun bulduğunuz herhangi bir makul biçimde olabilir.

En sevdiğiniz kitaplık / dilin sağladığı sahte rastgele üreteci kullanabilirsiniz.

N, k> 0 tamsayılarını varsayabiliriz.

Misal

Say n, k = 2. Azalmayan sekanslar

1,1
1,2
2,2

Her sekansın çıkma olasılığı 1/3 olmalıdır.

kısıtlama

Kodunuz k = 20 ve n = 100 için birkaç saniyeden fazla çalışmamalıdır.

Ne işe yaramaz

Her tamsayıyı 1'den n'ye kadar rastgele örneklerseniz ve listeyi sıralarsanız, tekdüze bir dağılım elde edemezsiniz.


N için k azalmayan dizilerin sayısını çıkarmak, henüz yapılmadıysa, kendi başına ilginç bir meydan okuma yapabilir ...
ETHproductions

1
@ETHproductions Pek değil, öyle bir binom sadece (ilgili bu )
SP3000

@ Sp3000 Ah, tamam. Yine de verimli bir şekilde nasıl hesaplayacağımı bulmak benim için eğlenceli bir mücadeleydi.
ETHproductions

Her sekansın eşit çıkma olasılığına sahip olma gereksiniminiz, sadece 32 veya 48 bit durumları olabilen çoğu bahçe çeşidi PRNG'si ile tatmin etmek mümkün değildir. Wolfram'a göre, 1, ..., 100'ün 535 quintillion 20 element alt dizisi var (kaç tanesinin azaldığını kontrol etmedi). 2 ^ 64 sadece 18 quintillion.
Sinan Ünür

Yanıtlar:


1

Aslında , 14 12 bayt

Bu cevap Emigna'nın 05AB1E cevabı ve bu Math.SE sorusundaki cevaplara dayanmaktadır . Golf önerileri hoş geldiniz! Çevrimiçi deneyin!

;;ra+DR╚HS♀-

Ungolfing

      Implicit input n, then k.
;;    Duplicate k twice.
r     Push range [0...k] for later.
a     Invert the stack. Stack: n, k, k, [0...k]
+DR   Push the range [1..n+k-1].
╚     Shuffle the range. Stack: shuffled_range, k, [0...k]
H     Push the first k elements of shuffled_range. Call this increasing.
S     Sort increasing so the elements are actually increasing.
♀-    Subtract each element of [0...k] from each element of increasing.
      This gives us our non-decreasing sequence.
      Implicit return.

13

Python, 89 bayt

from random import*
lambda n,k:[x-i for i,x in enumerate(sorted(sample(range(1,n+k),k)))]

Azalan olmayan bir sekanstan ziyade artan bir sekans oluşturmak basittir: bu, ve arasında sıralanan rastgele bir sayı alt kümesidir .k1n

Ancak, ardışık sayılar arasındaki her boşluğu 1 oranında daraltarak, artan bir sekansı, azalmayan bir sekansa dönüştürebiliriz. Böylece, 1'lik bir boşluk, eşit sayılar yaparak 0'lık bir boşluk haline gelir. Bunu yapmak için, en ibüyük değerii

r[0], r[1], ..., r[n-1]  =>  r[0]-0, r[1]-1, ..., r[n-1]-(n-1)

Sonucun ile arasında 1olması niçin girişin ile arasında 1olmalıdır n+k-1. Bu azalmayan arasında sayı dizileri arasında bir eşleşme veren 1ve narasındaki dizileri artan, 1ve n+k-1. Aynı diziler, bu tür dizileri saymak için yıldızlar ve çubuklar argümanında kullanılır .

Kod piton işlevini kullanan random.samplealır, kgiriş listesinden değiştirmeden örnekleri. Sıralamak, artan sekansı verir.


Bu etkileyici. Lütfen yöntemin bir açıklamasını ekleyebilir misiniz?

Şimdi meşgul olan Yup, daha sonra açıklayacak.
xnor

90 bayt saydım ... (ve ayrıca import*1 bayt tasarruf edebilirsiniz )
Rod

@ Rod Teşekkürler, bunu unuttum.
xnor

7

05AB1E , 13 bayt

+<L.r¹£{¹L<-Ä

Çevrimiçi deneyin!

açıklama

+<L            # range [1 ... n+k-1]
   .r          # scramble order
     ¹£        # take k numbers
       {       # sort
        ¹L<-   # subtract from their 0-based index
            Ä  # absolute value

7

Python, 87 bayt

from random import*
f=lambda n,k:k>random()*(n+k-1)and f(n,k-1)+[n]or k*[7]and f(n-1,k)

Olası maksimum değerin ndahil olma olasılığı eşittir k/(n+k-1). Eklemek için listenin sonuna yerleştirin ve kalan gerekli sayıları azaltın k. Hariç tutmak için üst sınırı azaltın n. Ardından, daha fazla değer gerekmeyene kadar tekrarlayın ( k==0).

Python's randombir Bernoulli değişkeni için yerleşik değildir: 1 olasılıkla 1, aksi takdirde 0. Bu nedenle, 0 ile 1 arasında rastgele bir değerin randomaşağıya düşüp düşmediğini kontrol eder k/(n+k-1). Python 2 olur şamandıra bölümü olarak oran, bu yüzden yerine çarpma ile payda: k>random()*(n+k-1).


Numpy burada yardımcı olur mu?

@Lembik İyi düşünülmüş, ama içe aktarmanız gerekecek gibi görünüyor numpy.random, ki bu çok uzun.
xnor

5

JavaScript (Firefox 30+), 74 bayt

(n,k,i=0,j=k)=>[for(_ of Array(q=k+n-1))if(Math.random(++i)<k/q--)i-j+k--]

açıklama

xnor'ın mükemmel Python cevabı , burada kullanılan tekniğin nasıl / neden çalıştığının çok iyi bir özetini içerir. İlk adım [1, 2, ..., n + k - 1] aralığını oluşturmaktır :

(n,k,i=0)=>[for(_ of Array(q=k+n-1))++i]

Sonra almak gerekir k bu aralıktan rastgele öğeleri. Bunu yapmak için, s / q olasılığı bulunan her bir öğeyi seçmemiz gerekir ; burada s , hala ihtiyaç duyulan öğe sayısıdır ve q , aralıkta kalan öğe sayısıdır. Bir dizi kavrayışı kullandığımız için, bu oldukça kolaydır:

(n,k,i=0)=>[for(_ of Array(q=k+n-1))if(Math.random(++i)<k/q--)k--&&i]

Bu da bize, homojen olarak dağıtılmış verir artan sayı dizisini. Bu, daha önce bulduğumuz j öğelerinin sayısının çıkarılmasıyla düzeltilebilir :

(n,k,i=0,j=0)=>[for(_ of Array(q=k+n-1))if(Math.random(++i)<k/q--)k--&&i-j++]

Son olarak, saklayarak k içinde j , biz dahil edebilirsiniz k--ifadeye ve birkaç bayt tasarruf:

(n,k,i=0,j=k)=>[for(_ of Array(q=k+n-1))if(Math.random(++i)<k/q--)i-j+k--]

2

TI-BASIC, 54 Bayt

Prompt N,K
K→dim(L1
While K
If rand<K/(N+K-1
Then
N→L1(K
K-1→K
Else
N-1→N
End
End
Disp L1

Küçük bir uyarı ile xnor'ın mantığını izleyin. Teorik olarak böyle bir şey yaparak bir baytı tıraş edebiliriz:

K>rand(N+K-1

Ancak rand (rastgele sayılar listesi oluşturmak için ayrılmıştır, bu nedenle bir bayt kaydetmek için istenen örtülü çarpımı yapamayız.

Bu kısıtlama başına 84 + terbiyeli hızlı çalışması gerekir ama ne zaman yapabilirim emin olmak için kontrol edeceğiz.


1

PHP, 77 75 73 bayt

foreach(array_rand(range(2,$argv[1]+$k=$argv[2]),$k)as$v)echo$v+1-$i++,_;

Şu şekilde çalıştırın:

php -r 'foreach(array_rand(range(2,$argv[1]+$k=$argv[2]),$k)as$v)echo$v+1-$i++,_;' -- 10 5 2>/dev/null;echo
> 1_4_6_9_9_

açıklama

foreach(                    # Iterate over...
  array_rand(               #   a (sorted) random number of items from...
    range(                  #     an array with items...
      2,                    #       from 2
      $argv[1]+$k=$argv[2]  #       to n + k (set arg 2 to $k)
    ),
    $k                      #     Take k number of items (their keys)
  )
  as $v
)
  echo $v +1 - $i++,"_";    # Print the value subtracted by the index.
                            # Need to add 1, because keys are 0-indexed.

Düzenlemeler

  • Kaldırarak 2 bayt Kaydedilen end()aramayı ve set $argv[2]için $ktartışmalara kısaltın erişim yerine
  • Dizini foreach'ten kaldırarak 2 bayt kaydedildi, çünkü bu sadece artan bir sayı. Bunun $iyerine her yinelemeyi artırın

İlk JavaScript ve şimdi PHP. En iyi bilimsel programlama dilleri :) Teşekkürler.

@Lembik, rica ederim. Dikkat edin, temel bir PRNG kullanır. Kriptografik şeyler için kullanmayın . :)
16:28
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.