ตัวอย่างลำดับแบบไม่ลด


20

อินพุต:สองจำนวนเต็ม n และ k ที่กำหนดในรูปแบบใด ๆ ที่สะดวกสำหรับรหัสของคุณ

เอาท์พุทลำดับที่ไม่ลดลงแบบสุ่มของจำนวนเต็ม k แต่ละค่าในช่วง 1 ถึง n ควรเลือกตัวอย่างอย่างสม่ำเสมอจากลำดับที่ไม่ลดจำนวนทั้งหมดของ k จำนวนเต็มด้วยจำนวนเต็มในช่วง 1 ถึง n

เอาต์พุตสามารถอยู่ในรูปแบบที่สมเหตุสมผลที่คุณเห็นว่าสะดวก

คุณสามารถใช้เครื่องกำเนิดไฟฟ้าแบบสุ่มหลอกสิ่งที่คุณชื่นชอบห้องสมุด / ภาษาให้

เราสามารถสรุปได้ว่าจำนวนเต็ม n, k> 0

ตัวอย่าง

พูดว่า n, k = 2 ลำดับที่ไม่ลดลงคือ

1,1
1,2
2,2

แต่ละลำดับควรมีความน่าจะเป็น 1/3 ของผลลัพธ์

การ จำกัด

รหัสของคุณควรทำงานในไม่เกินสองสามวินาทีสำหรับ k = 20 และ n = 100

อะไรไม่ทำงาน

หากคุณเพียงแค่สุ่มแต่ละจำนวนเต็มแบบสุ่มจากช่วง 1 ถึง n จากนั้นเรียงลำดับรายการคุณจะไม่ได้การแจกแจงแบบสม่ำเสมอ


เอาท์พุทจำนวนของลำดับที่ไม่ลดลงสำหรับ n, k อาจทำให้ความท้าทายที่น่าสนใจด้วยตัวเองถ้ามันยังไม่ได้ทำ ...
ETHproductions

1
@ETHproductions ไม่จริงมันเป็นเพียงทวินาม (เกี่ยวข้องกับเรื่องนี้ )
Sp3000

@ Sp3000 Ah, OK มันเป็นความท้าทายที่สนุกสำหรับฉันที่จะหาวิธีการคำนวณอย่างมีประสิทธิภาพ
ETHproductions

ความต้องการของคุณที่แต่ละลำดับมีความน่าจะเป็นที่เท่ากันของการส่งออกเป็นไปไม่ได้ที่จะพึงพอใจกับ PRNG ที่หลากหลายในสวนซึ่งอาจมีสถานะ 32 หรือ 48 บิต ตาม Wolfram มีองค์ประกอบ 535 quintillion 20 องค์ประกอบของ 1, ... , 100 (ไม่ได้ตรวจสอบว่าจำนวนของพวกเขาจะไม่ลดลง) 2 ^ 64 เป็นเพียง 18 ล้านล้าน
Sinan Ünür

คำตอบ:


1

อันที่จริง , 14 12 ไบต์

คำตอบนี้ขึ้นอยู่กับคำตอบ 05AB1E ของ Emignaและคำตอบสำหรับคำถาม Math.SEนี้ ยินดีต้อนรับคำแนะนำการเล่นกอล์ฟ! ลองออนไลน์!

;;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 ไบต์

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

การสร้างลำดับที่เพิ่มขึ้นแทนที่จะเป็นแบบที่ไม่ลดลงจะตรงไปตรงมา: นี่เป็นเพียงส่วนย่อยของkตัวเลขแบบสุ่มระหว่าง1และnเรียงลำดับ

แต่เราสามารถแปลงลำดับที่เพิ่มขึ้นเป็นหนึ่งที่ไม่ลดลงโดยการลดขนาดแต่ละช่องว่างระหว่างตัวเลขที่ต่อเนื่องกันด้วย 1 ดังนั้นช่องว่าง 1 กลายเป็นช่องว่างของ 0 ทำให้ตัวเลขที่เท่ากัน หากต้องการทำเช่นนั้นให้ลดiค่าที่มากที่สุดโดยi

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

สำหรับผลที่ได้จะมาจาก1การnป้อนข้อมูลจะต้องมาจากการ1 n+k-1นี้จะช่วยให้ bijection ระหว่างลำดับที่ไม่ลดลงของตัวเลขระหว่าง1และnจะเพิ่มขึ้นระหว่างลำดับและ1 n+k-1bijection ที่เหมือนกันถูกใช้ในการโต้แย้งดาวและแถบสำหรับการนับลำดับดังกล่าว

รหัสใช้ฟังก์ชัน python random.sampleซึ่งรับkตัวอย่างโดยไม่ต้องเปลี่ยนจากรายการอินพุต การเรียงลำดับจะให้ลำดับที่เพิ่มขึ้น


อันนี้น่าประทับใจ คุณช่วยเพิ่มคำอธิบายของวิธีการได้ไหม?

ใช่ไม่ว่างตอนนี้จะอธิบายในภายหลัง
xnor

ฉันนับ 90 ไบต์ ... (และคุณสามารถimport*บันทึกได้ 1 ไบต์)
Rod

@ Rod ขอบคุณฉันลืมไปแล้ว
xnor


7

Python ขนาด 87 ไบต์

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)

ความน่าจะเป็นที่ค่าสูงสุดที่เป็นไปได้nรวมอยู่k/(n+k-1)ด้วย หากต้องการรวมให้วางไว้ที่ส่วนท้ายของรายการและลดจำนวนที่kต้องการ nหากต้องการยกเว้นมันพร่องผูกพันบน จากนั้นเรียกคืนจนกว่าจะไม่มีค่าเพิ่มเติมอีกต่อไป ( k==0)

Python randomดูเหมือนจะไม่มีตัวแปรในตัวสำหรับตัวแปร Bernoulli: 1 ที่มีความน่าจะเป็นบางอย่างและ 0 เป็นอย่างอื่น ดังนั้นการตรวจสอบนี้หากค่าสุ่มระหว่าง 0 และ 1 ที่สร้างขึ้นโดยลดลงต่ำกว่าrandom k/(n+k-1)งูหลาม 2 k>random()*(n+k-1)จะอัตราส่วนตามที่ส่วนลอยเพื่อให้เราแทนคูณหาร:


คนอ้วนจะช่วยที่นี่ไหม?

@ Lembik ความคิดที่ดี แต่ดูเหมือนว่าคุณจะต้องนำเข้าnumpy.randomซึ่งยาวเกินไป
xnor

5

JavaScript (Firefox 30+), 74 ไบต์

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

คำอธิบาย

คำตอบ Python ที่ยอดเยี่ยมของ xnorมีการสรุปที่ดีมากว่า / ทำไมเทคนิคที่ใช้ในการทำงานที่นี่ ขั้นตอนแรกคือการสร้างช่วง[1, 2, ... , n + k - 1] :

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

ต่อไปเราจำเป็นต้องนำรายการสุ่มkจากช่วงนี้ ในการทำเช่นนี้เราจำเป็นต้องเลือกแต่ละรายการด้วยความน่าจะเป็น s / qโดยที่sคือจำนวนของรายการที่ต้องการและqคือจำนวนรายการที่เหลือในช่วง เนื่องจากเราใช้ความเข้าใจของอาเรย์จึงค่อนข้างง่าย:

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

นี่ทำให้เรามีการกระจายของตัวเลขที่เพิ่มขึ้นอย่างสม่ำเสมอ สิ่งนี้สามารถแก้ไขได้โดยการลบจำนวนรายการjที่เราพบก่อนหน้านี้:

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

สุดท้ายโดยการจัดเก็บkในjเราสามารถรวมk--เข้ากับนิพจน์และบันทึกสองสามไบต์:

(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 ไบต์

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

ตรรกะของ xnor ของ Follower ที่มีข้อแม้เล็ก ๆ ในทางทฤษฎีเราสามารถโกนไบต์ได้โดยทำสิ่งนี้:

K>rand(N+K-1

แต่แรนด์ (สงวนไว้เพื่อสร้างรายการของตัวเลขสุ่มดังนั้นเราจะไม่สามารถทำการคูณโดยนัยที่ต้องการเพื่อบันทึกไบต์

การดำเนินการนี้ควรดำเนินการอย่างรวดเร็วในระดับ 84+ ต่อข้อ จำกัด แต่ฉันจะตรวจสอบเพื่อให้แน่ใจว่าเมื่อใดที่ฉันสามารถทำได้


1

PHP, 77 75 73 ไบต์

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

ทำงานแบบนี้:

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_

คำอธิบาย

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.

การปรับแต่ง

  • บันทึก 2 ไบต์โดยลบการend()โทรออกและตั้งค่า$argv[2]เป็น$kแทนเพื่อลดการเข้าถึงอาร์กิวเมนต์
  • บันทึก 2 ไบต์โดยลบดัชนีออกจาก foreach เนื่องจากเป็นเพียงตัวเลขที่เพิ่มขึ้น เพียงเพิ่ม$iแต่ละการวนซ้ำแทน

JavaScript แรกและตอนนี้ PHP ภาษาการเขียนโปรแกรมทางวิทยาศาสตร์ที่ดีที่สุด :) ขอบคุณ

@ Lembik ยินดีต้อนรับ ใจคุณใช้ PRNG พื้นฐาน อย่าใช้สำหรับสิ่งที่เข้ารหัสลับ :)
aross
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.