किसी दिए गए यादृच्छिक संख्या जनरेटर का उपयोग करके 1-100 प्रिंट करने के लिए सबसे कुशल एल्गोरिदम


11

हमें एक यादृच्छिक संख्या जनरेटर दिया जाता है RandNum50जो एक यादृच्छिक पूर्णांक को 1-50 की सीमा में समान रूप से उत्पन्न करता है। हम सभी पूर्णांकों को यादृच्छिक क्रम में 1 से 100 तक उत्पन्न और प्रिंट करने के लिए केवल इस यादृच्छिक संख्या जनरेटर का उपयोग कर सकते हैं। हर नंबर को एक बार बिल्कुल आना चाहिए, और किसी भी स्थान पर होने वाली किसी भी संख्या की संभावना बराबर होनी चाहिए।

इसके लिए सबसे कुशल एल्गोरिदम क्या है?


1
पहले से ही देखी गई संख्याओं को रिकॉर्ड करने के लिए एक सरणी / या बिट वेक्टर का उपयोग करें और देखा गया अद्वितीय संख्याओं को रिकॉर्ड करने के लिए एक काउंटर।
डेव क्लार्क

@DaveClarke मैं उसके साथ 50 से बड़ी संख्या कैसे उत्पन्न कर सकता हूं? यदि मैं इसे 1 से अधिक बार उपयोग करता हूं, तो मैं भी, मैं उनका उपयोग करके 1 कैसे उत्पन्न करूंगा?
राज वाधवा

1
पाठ्यक्रम की चुनौती यह सुनिश्चित कर रही है कि सभी जगह समान संभावना के साथ हो। आप उपयोग कर सकते हैं RandNum100 = (RandNum50() * 2) - (RandNum50 > 25) ? 0 : 1)
डेव क्लार्क

2
@DaveClarke: तो आप पुनरावृत्त अस्वीकृति नमूने का प्रस्ताव है? यह केवल अपेक्षा में समाप्त होगा।
राफेल

मैं केवल इशारा दे रहा था।
डेव क्लार्क

जवाबों:


3

मैंने सोचा (इसलिए यह गलत हो सकता है :-) इस समाधान का जो फिशर-येट्स फेरबदल का उपयोग करता है । प्रत्येक सन्निकटन में अच्छे सन्निकटन (नीचे EDIT अनुभाग देखें) के साथ समान वितरण रखने के लिए आप इस चाल का उपयोग और बीच मान उत्पन्न करने के लिए कर सकते हैं :0 के - 1O(N2)krand0k1

 // 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
 }

फिशर-येट्स एल्गोरिथ्म बन जाता है:

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]

संपादित करें:

जैसा कि Erick द्वारा बताया गया है, krandउपरोक्त फ़ंक्शन सही मायने में एक समान वितरण वापस नहीं करता है। अन्य विधियां हैं जिनका उपयोग बेहतर (मनमाने ढंग से बेहतर) और तेजी से सन्निकटन प्राप्त करने के लिए किया जा सकता है; लेकिन (ऊपर मेरी जानकारी के लिए) वास्तव में एक समान वितरण प्राप्त करने के लिए एक ही रास्ता उपयोग करने के लिए है अस्वीकृति नमूना : लेने यादृच्छिक बिट और यदि संख्या प्राप्त की तुलना में कम है यह वापसी, अन्यथा एक और यादृच्छिक संख्या उत्पन्न करें; एक संभावित कार्यान्वयन:आर कश्मीरm=log2(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
आप जिस विकिपीडिया पृष्ठ को लिंक करते हैं, वह बताता है कि संस्करण है। O(n)
डेव क्लार्क

1
मुझे लगता है कि "फेरबदल" यहां मुख्य चर्चा है।
राफेल

4
क्रंद (k) में चाल वास्तव में एक समान वितरण का उत्पादन नहीं करती है, हालांकि यह एक अच्छा सन्निकटन है: यहां तक ​​कि k = 3 के लिए यह 33.333328% आउटपुट का मौका देता है। 0. क्या कश्मीर के लिए सभी तरह से योग करने का औचित्य है ? मुझे लगता है कि अगर हम सिर्फ एक अनुमान चाहते हैं तो एक छोटी सीमा पर्याप्त होगी।
एरिक वोंग

1
@ एरिकवॉन्ग: आप सही हैं; मुझे लगता है कि असली वर्दी वितरण केवल अस्वीकृति नमूनाकरण विधि का उपयोग करके तक पहुँचा जा सकता है जो निरंतर समय में समाप्त होने की गारंटी नहीं है। अन्य सन्निकटन योजनाएं हैं (जो किसी भी वांछित सन्निकटन तक पहुंचने की अनुमति देती हैं), मैंने जो प्रस्तावित किया वह पहला है जो मेरे दिमाग में आया था।
वोर

2
@ ex0du5: मुझे पता है कि, लेकिन आप [1..100] में केवल एक समान यादृच्छिक जनरेटर का उपयोग करके संख्याओं का एक समान यादृच्छिक क्रमांकन [1..100] कैसे उत्पन्न करते हैं? एकमात्र वैकल्पिक विधि जो मुझे पता है वह है: चरण 1) में एक यादृच्छिक मान ; step2) अगर पहले ही उठाया जा चुका है तो इसे त्यागें और goto step1; चरण 3) प्रिंट ; step4) अगर हमने सभी 100 नंबरों के गोटो step1 को प्रिंट नहीं किया है। लेकिन यह विधि केवल पहले से ही चुने गए तत्वों की अस्वीकृति को स्थानांतरित करती है। 1..100 r rr1..100rr
Vor

4

चूंकि अन्य लोगों ने अनुमानित समाधान और समाधान दिए हैं, जिसमें भक्तों की अनिश्चित संख्या को शामिल करना है, कैसे एक सबूत के बारे में कि ऐसा कोई एल्गोरिथ्म नहीं है जो केवल RandNum50()कॉल की एक सीमित संख्या की आवश्यकता की गारंटी देता है ?

जैसा कि अन्य ने उल्लेख किया है, यादृच्छिक क्रम में 1-100 से संख्याओं को प्रिंट करना इन संख्याओं के यादृच्छिक क्रमांकन को प्रिंट करने के बराबर है; 100 हैं! इन क्रमपरिवर्तन, और इसलिए किसी भी विशेष क्रमपरिवर्तन को प्रायिकता साथ आउटपुट होना चाहिए ।1100!

लेकिन अगर हम जानते थे कि हमारे एल्गोरिथ्म ज्यादा से ज्यादा इस्तेमाल किया कॉल करने के लिए कुछ के लिए , तो हम बहस कर सकते के रूप में इस प्रकार है: पहला, बाहर उन गणना रास्तों कि तुलना में कम कर पैड के लिए कॉल अतिरिक्त डमी कॉल करने के लिए (जो है, कॉल जहाँ लौटाया गया मान अप्रासंगिक है), जिससे सभी संगणना पथ ठीक कॉल करते हैं। हमारे कॉल से परिणामों का कोई भी क्रम कुछ आउटपुट क्रमोन्नति में परिणत होना चाहिए, और इसलिए हम एक विशेष परिणामों में किसी भी अनुक्रम के नक्शे का निर्माण कर सकते हैं। उत्पादन क्रमचय। चूंकि इनमें से प्रत्येक परिणाम समान रूप से संभव है (उनमें से प्रत्येक में संभावना हैk k k k ( r 1 , r 2 , , r k ) 1kRandNum50kkRandNum50kkRandNum50(r1,r2,,rk) c150k ), तो हमारे एल्गोरिथम में से किसी विशेष क्रमचय को प्राप्त करने की संभावना कुछ के लिए form होनी चाहिए । लेकिन इस फ़ॉर्म का नहीं हो सकता, क्योंकिविभाजित नहीं करता है से किसी के लिए (उदाहरण के लिए, 3 विभाजित लेकिन फार्म के किसी भी संख्या विभाजित नहीं कर सकते )। इसका मतलब यह है कि यादृच्छिक-संख्या कॉल के परिणामों का कोई संभावित वितरण एक समान क्रमचय का उत्पादन नहीं कर सकता है। c1c50kc100! 50kk100! 50कश्मीर1100!100!50kk100!50k


2

पिछले समाधान इष्टतम नहीं हैं। जटिलता RandNum50 के लिए कॉल में बिल्कुल है और इसे यादृच्छिक रूप से बिट के स्रोत के रूप में उपयोग करते हुए यहां कुछ विवरण में वर्णित किया गया है (जैसा कि Vor द्वारा सुझाया गया है):nlogn+O(1)

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

मूल विचार यह है कि यदि आप और बीच एक समान उत्पन्न करते हैं, तो आप बहुत सारे बिट्स बचाते हैं, और फिर फैक्टोरियल बेस अपघटन का उपयोग करते हुए , वर्दी का एक क्रम उत्पन्न करने के बजाय , फिर , फिर , आदि, । यह वास्तव में है, जैसा कि मैंने पोस्ट में उल्लेख किया है, एक पेपर का विषय जो मैंने प्रस्तुत किया है!एन ! 1 2 3 एन1n!123n

यदि आप यह नहीं जानते हैं कि वर्दी कैसे उत्पन्न की जाती है, जैसा कि उस पोस्ट में बताया गया है, तो एक यादृच्छिक बिट से, आप सीधे वर्दी का एक अनुमान भी उत्पन्न कर सकते हैं, इस तरह से (जो वोर के "सही मायने में" के बराबर है, लेकिन तेजी से):

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

जहां तक ​​जाने की जरूरत है, वहां जाना। यह बेस में विकसित कर रहा है । तो बस आपके मामले में , यानी, काट देना चाहिए। यह मान पूरी तरह से यादृच्छिक नहीं है, लेकिन यह एकरूपता का एक उपाय है जो अक्सर उपयोग किया जाता है। या, जैसा कि Vor बताता है, आप को अस्वीकार कर सकते हैं । फिर इस मान के साथ, आप पोस्ट में वर्णित तथ्यात्मक आधार विस्तार कर सकते हैं ।50 पीP50Pn = 100 !Q=Pmodnn=100!P>n


1

मैं इस बात की पुष्टि करने के लिए विश्लेषण नहीं किया है कि कैसे एक समान (या नहीं) इस होगा, और यह एक सच फेरबदल होने की समायोजित किया जा सकता है, लेकिन तुम सिर्फ का कोई आरंभिक सरणी से, चुन सकते हैं iवीं सूचकांक = i + 1, (k + RandNum50() + RandNum50() - 1) mod (100 - k)सूचकांक, के साथ हटाने, के लिए k= 0..99?

यह " RandNum50() + RandNum50()समान रूप से वितरण को आगे " शिखर पर धकेलता है ।

मुझे पूरा यकीन है कि यह बिल्कुल सही नहीं है क्योंकि मैंने इसे कहा है क्योंकि पहली पसंद से 0 सूचकांक (1) प्राप्य नहीं है और मैं जल्दी से एक वैकल्पिक 1..50 + 1..50 समायोजन नहीं देख सकता है जो 0 का उत्पादन करता है। ..99।

अपडेट करें

मेरे द्वारा नोट की गई समस्या को ठीक करने के लिए, मैंने RandNum100पहले kऑफसेट को बेतरतीब ढंग से आरंभ करने के लिए प्रश्न टिप्पणियों में प्रभावी रूप से उल्लेख किया ।

यह मोर्चे पर एक महत्वपूर्ण लहर के साथ एक वितरण पैदा करता है।

1 से आगे बढ़ने के बजाय मैंने RandNum50पहले वेतन वृद्धि के लिए एक और प्रयोग किया k। यह एक ऐसा परिणाम पैदा करता है जो मेरे लिए पर्याप्त यादृच्छिक है, लेकिन यह अभी भी "सही मायने में" यादृच्छिक नहीं है, जैसा कि आसानी से देखा जा सकता है यदि आप K को 2 में बदलते हैं।

VB.NET कोड का परीक्षण जहां मैंने किसी K के लिए भी नोट किया था। ध्यान दें कि यह वास्तव में O (K), 6K + 2 है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.