# 3 दिन का यादृच्छिक गोल्फ: पूर्णांक विभाजन


19

श्रृंखला के बारे में

सबसे पहले, आप इसे किसी अन्य कोड गोल्फ चुनौती की तरह मान सकते हैं, और श्रृंखला के बारे में चिंता किए बिना इसका जवाब दे सकते हैं। हालांकि, सभी चुनौतियों के बीच एक लीडरबोर्ड है। आप लीडरबोर्ड के साथ पहली पोस्ट में श्रृंखला के बारे में कुछ और जानकारी पा सकते हैं ।

यद्यपि मेरे पास श्रृंखला के लिए विचारों का एक समूह है, लेकिन भविष्य की चुनौतियां अभी तक पत्थर में सेट नहीं हैं। यदि आपके कोई सुझाव हैं, तो कृपया मुझे संबंधित सैंडबॉक्स पोस्ट पर बताएं ।

छेद 3: पूर्णांक विभाजन

कठिनाई को थोड़ा बढ़ाने का समय।

एक सकारात्मक पूर्णांक के एक विभाजन को सकारात्मक पूर्णांक के nएक बहु के रूप में परिभाषित किया गया है जो योग है n। एक उदाहरण के रूप में अगर n = 5, निम्नलिखित विभाजन मौजूद हैं:

{1,1,1,1,1}
{2,1,1,1}
{2,2,1}
{3,1,1}
{3,2}
{4,1}
{5}

ध्यान दें कि ये मल्टीसेट हैं, इसलिए उनके लिए कोई ऑर्डर नहीं है {3,1,1}, {1,3,1}और {1,1,3}सभी को समान माना जाता है।

का nएक यादृच्छिक विभाजन उत्पन्न करने के लिए आपका कार्य दिया गया है n। यहाँ विस्तृत नियम हैं:

  • उत्पादित विभाजन का वितरण एक समान होना चाहिए । यही है, उपरोक्त उदाहरण में, प्रत्येक विभाजन को 1/7 संभावना के साथ वापस किया जाना चाहिए।

    बेशक, PRNGs की तकनीकी सीमाओं के कारण, सही एकरूपता असंभव होगी। आपके सबमिशन की एकरूपता का आकलन करने के उद्देश्य से, निम्नलिखित कार्यों को पूरी तरह से समान वितरण प्रदान करने के रूप में माना जाएगा:

    • PRNG (किसी भी सीमा से अधिक) से एक संख्या प्राप्त करना, जो कि (लगभग) एकरूप होने के लिए प्रलेखित है।
    • मॉडुलो या गुणा (या कुछ अन्य ऑपरेशन जो समान रूप से मान वितरित करता है) के माध्यम से एक छोटे सेट पर संख्याओं के एक बड़े सेट पर एक समान वितरण का मानचित्रण करता है। बड़े सेट में छोटे सेट के रूप में कम से कम 1024 गुना अधिक संभव मान होते हैं।
  • चूंकि विभाजन मल्टीसेट्स हैं, आप उन्हें किसी भी क्रम में वापस कर सकते हैं, और इस आदेश को लगातार नहीं होना चाहिए। हालांकि, यादृच्छिक वितरण के उद्देश्य के लिए, आदेश की अनदेखी की जाती है। अर्थात्, उपरोक्त उदाहरण में {3,1,1}, {1,3,1}और {1,1,3} साथ में 1/7 की वापसी की संभावना होनी चाहिए।

  • आपके एल्गोरिथ्म में एक नियतात्मक रनटाइम होना चाहिए विशेष रूप से, आप रैंडम मल्टीसेट्स उत्पन्न नहीं कर सकते हैं और यदि उन्हें योग नहीं करते हैं तो उन्हें अस्वीकार कर सकते हैं n
  • आपके एल्गोरिथ्म की समय जटिलता बहुपद में होनी चाहिए n। विशेष रूप से, आप बस सभी विभाजन उत्पन्न नहीं कर सकते हैं और एक यादृच्छिक एक का चयन कर सकते हैं (चूंकि विभाजन की संख्या तेजी से बढ़ती है n)। आप मान सकते हैं कि आप जिस PRNG का उपयोग कर रहे हैं, वह O (1) प्रति मान में समान रूप से वितरित मान लौटा सकता है।
  • आपको किसी भी अंतर्निहित फ़ंक्शन का उपयोग नहीं करना चाहिए जो इस कार्य को हल करता है।

आप एक पूर्ण कार्यक्रम या फ़ंक्शन लिख सकते हैं और एसटीडीआईएन या निकटतम विकल्प, कमांड-लाइन तर्क या फ़ंक्शन तर्क के माध्यम से इनपुट ले सकते हैं और रिटर्न वैल्यू के माध्यम से या एसटीडीयूएसटी (या निकटतम विकल्प) पर प्रिंट करके आउटपुट का उत्पादन कर सकते हैं।

आप ऐसा मान सकते हैं n ≤ 65(जैसे कि विभाजन की संख्या 2 21 से कम है )। आउटपुट किसी भी सुविधाजनक, अस्पष्ट सूची या स्ट्रिंग प्रारूप में हो सकता है।

यदि आप एक फ़ंक्शन सबमिट करते हैं, तो कृपया थोड़ा परीक्षण कार्यक्रम प्रदान करने पर विचार करें जो फ़ंक्शन को कई बार कॉल करता है और परिणामों को प्रिंट करता है। यह ठीक है अगर पैरामीटर को कोड में घुमाया जाना है। यह सिर्फ इतना है कि लोग जांच सकते हैं कि समाधान कम से कम लगभग समान है।

यह कोड गोल्फ है, इसलिए सबसे छोटा सबमिशन (बाइट्स में) जीतता है। और निश्चित रूप से, प्रति उपयोगकर्ता सबसे कम सबमिशन भी श्रृंखला के समग्र लीडरबोर्ड में प्रवेश करेगा।

लीडरबोर्ड

श्रृंखला की पहली पोस्ट एक लीडरबोर्ड उत्पन्न करती है।

यह सुनिश्चित करने के लिए कि आपके उत्तर दिखाए गए हैं, कृपया प्रत्येक मार्कलाइन के साथ निम्नलिखित मार्केड टेम्प्लेट का उपयोग करके प्रत्येक उत्तर को शुरू करें:

# Language Name, N bytes

Nआपके सबमिशन का आकार कहां है। यदि आप अपने स्कोर में सुधार करते हैं, तो आप पुराने अंकों को हेडलाइन में रख सकते हैं , उनके माध्यम से स्ट्राइक करके। उदाहरण के लिए:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(भाषा को वर्तमान में नहीं दिखाया गया है, लेकिन स्निपेट की आवश्यकता होती है और इसे पार्स किया जाता है, और मैं भविष्य में एक उप-भाषा लीडरबोर्ड जोड़ सकता हूं।)

जवाबों:


8

पायथन 2, 179 बाइट्स

from random import*
m=r=input();i=q=r+1;h=[1]+[0]*q*q;exec"h[i]=h[i+~q]+h[i-i%q*q];i+=1;"*r*q
while r:
 x=random()*sum(h[r*q:r*q-~m]);m=0
 while x>0:m+=1;x-=h[r*q+m]
 print m;r-=m

मैंने इस नूथ एक्सट्रैक्ट से फॉर्मूला (39) का इस्तेमाल किया , जिससे nइसके mकुछ हिस्सों के विभाजन के बारे में पता चलता है । इस के विभाजन की संख्या के बराबर करने के लिए होता nहै कि mअधिक से अधिक तत्व है, जो व्याख्या मैं उपयोग कर रहा हूँ के रूप में। विभाजन के तत्व सबसे बड़े से कम से कम उत्पन्न होते हैं। प्रत्येक चरण में सूत्र का वर्तमान शेष nऔर अधिकतम अनुमत तत्व के साथ पुन: उपयोग किया जाता है ।


5

डायलॉग एपीएल, 67 59 51 बाइट्स

p←{⍵,⊂1,⍨+/¨⌽⍵↑¨⍨⌽⍳⍴⍵}⍣⎕⊢⍬⋄f←{⍵=0:⍬⋄a,a∇⍵-a←{1++/(?+/⍵)>+\⍵}⍺↑⍵⊃p}⍨ (67 बाइट्स)

pवैक्टर का एक वेक्टर जिसमें है p[n][k]के विभाजन की संख्या है nमें kसबसे बड़ी योज्य के साथ विभाजन की संख्या: summands, या समतुल्य k। हम pखाली वेक्टर , रीडिंग n( रीड्स इनपुट) से शुरू करके और बार-बार निम्नलिखित को लागू करके बनाते हैं :

{⍵,⊂1,⍨+/¨⌽⍵↑¨⍨⌽⍳⍴⍵}
                 ⍴⍵   ⍝ the current length, initially 0
                ⍳⍴⍵   ⍝ 1 2 ... length
               ⌽⍳⍴⍵   ⍝ length ... 2 1
           ⍵↑¨⍨       ⍝ take length elements from p[1], length-1 from p[2], etc
                      ⍝ padded with 0-s, e.g. if p was (,1)(1 1)(1 1 1)(1 2 1 1)(1 2 2 1 1):
                      ⍝ we get:     (1 0 0 0 0)(1 1 0 0)(1 1 1)(1 2)(,1)
          ⌽           ⍝ reverse it: (,1)(1 2)(1 1 1)(1 1 0 0)(1 0 0 0 0)
       +/¨            ⍝ sum each:   1 3 3 2 1
    1,⍨               ⍝ append 1:   1 3 3 2 1 1
 ⍵,⊂                  ⍝ append the above to the vector of vectors

nअनुप्रयोगों ( ⍣⎕) के बाद , हमने बनाया है p

fएक यादृच्छिक विभाजन चुनता है। अधिकांश गर्मियों मेंn f k एक यादृच्छिक विभाजन है । है । kf nn f n

{⍵=0:⍬⋄a,a∇⍵-a←{1++/(?+/⍵)>+\⍵}⍺↑⍵⊃p}⍨
                                     ⍨ ⍝ "selfie" -- use n as k if no k is provided
 ⍵=0:⍬                                 ⍝ if n=0 return empty
                                 ⍵⊃p   ⍝ pick the n-th element of p
                               ⍺↑      ⍝ take k elements from that
               {1++/(?+/⍵)>+\⍵}        ⍝ use them as weights to pick a random number 1...k
               {           +\⍵}        ⍝   partial sums of weights
               {    (?+/⍵)    }        ⍝   a random number 1...sum of weights
               {    (?+/⍵)>+\⍵}        ⍝   which partial sums is it greater than?
               {  +/          }        ⍝   count how many "greater than"-s
               {1+            }        ⍝   we're off by one
             a←                        ⍝ this will be the greatest number in our partition
         a∇⍵-a                         ⍝ recur with n1=n-a and k1=a
       a,                              ⍝ prepend a

कुछ सुधार:

  • pथोड़ा खराब (लेकिन अभी भी काफी अच्छा) प्रदर्शन की कीमत पर इनलाइन

  • की गणना में pपुनर्व्यवस्थित करें और 1,करने के लिए एक चरित्र को बचाने

  • सामने वाली {1++/(?+/⍵)>+\⍵}ट्रेन में मुड़ें 1+:1+(+/(?+/)>+\)

  • बनाने के fएक गुमनाम समारोह और आपूर्ति एक तर्क एक पूरा कार्यक्रम प्राप्त करने के लिए के रूप में (eval'ed इनपुट)

{⍵=0:⍬⋄a,a∇⍵-a←1+(+/(?+/)>+\)⍺↑⍵⊃{⍵,⊂⌽1,+/¨⍵↑¨⍨⌽⍳⍴⍵}⍣⍵⊢⍬}⍨⎕ (59 बाइट्स)

N = 5 के साथ टेस्ट करें

N = 65 के साथ टेस्ट करें

और निम्न लिंक n = 5 हजारों बार चलता है और प्रत्येक विभाजन की आवृत्ति के बारे में आंकड़े इकट्ठा करता है: ⎕rl←0 ⋄ {⍺,⍴⍵}⌸ {⍵=0:⍬⋄a,a∇⍵-a←1+(+/(?+/)>+\)⍺↑⍵⊃{⍵,⊂⌽1,+/¨⍵↑¨⍨⌽⍳⍴⍵}⍣⍵⊢⍬}⍨ ¨10000⍴5


अधिक सुधार, रोजर हुई से मदद के साथ :

  • के {⍵=0:A⋄B}साथ बदलें {×⍵:B⋄A}। Signum ( ×⍵) के लिए सही ⍵>0और गलत है ⍵=0

  • के (+/(?+/)>+\)साथ बदलें +/b<?⊃⌽b←+\, यह एक चरित्र बचाता है

  • वेक्टर के बजाय मैट्रिक्स की गणना करने के लिए मैट्रिक्स का उपयोग करें p: के ⍵⊃{⍵,⊂⌽1,+/¨⍵↑¨⍨⌽⍳⍴⍵}⍣⍵⊢⍬साथ बदलें ⊃↓(0,⍨⊢⍪⍨1 1⍉+\)⍣⍵⍪1

{×⍵:a,a∇⍵-a←1++/b<?⊃⌽b←+\⍺↑⊃↓(0,⍨⊢⍪⍨1 1⍉+\)⍣⍵⍪1⋄⍬}⍨ (51 बाइट्स)

परीक्षण n = 5 ; परीक्षण एन = 65 ; फ्रीक आँकड़े


2
रोजर हुई से मदद कैसे मिलती है?
13 दिसंबर को फ्यूजेंकल

5
अपने आप को उसी कंपनी में रखने के लिए एक खिलौना एपीएल दुभाषिया लिखें। उपरोक्त अभिव्यक्ति को एक चुनौती के रूप में लें, अपने द्वारा लिए गए प्रत्येक चरित्र के लिए बीयर की एक पिंट का वादा करें। फिर लाभ: कम पात्र और अधिक उबाऊ क्योंकि वह बीयर नहीं पीता है।
ngn

1
समझा। यह एक साफ-सुथरी रणनीति है, आइए देखें कि क्या मैं पुन: पेश कर सकता हूं ... क्या आप उनसे पूछ सकते हैं कि क्या डायलाग एपीएल को u/\. yजल्द ही जे की तरह कुछ मिलने वाला है ?
फ्यूजएक्सएक्सएल

रिकॉर्ड के लिए: twitter.com/FUZxxl/status/572377068555644929
ngn

उसे पूछने के लिए धन्यवाद। अब मुझे आश्चर्य है कि क्या यह रैखिक समय में भी संभव है।
फ़ूजएक्सएक्सएल

4

गोल्फस्क्रिप्ट, 90 बाइट्स

~[[[1.]]]\({..[[{{(\{)}%+}%1$,1$,-=}%[1,]@0=+{1+}%]zip{{(\.,/*~}%.,.rand@=+}:^%]\+}*0=^(;`

ऑनलाइन डेमो

यह मेरे (सरल) विभाजन गिनती कोड का एक अनुकूलन है जो केवल एक गिनती पर नज़र रखने के बजाय एक गिनती और समान रूप से गिने तत्वों में से एक का चयन करता है।

दोनों की साथ-साथ तुलना:

~[[[1.]]]\({..[[{{(\{)}%+}%1$,1$,-=}%[1,]@0=+{1+}%]zip{{(\.,/*~}%.,.rand@=+}:^%]\+}*0=^(;`
 [[ 1  ]]\({..[[{          1$,1$,-=}%  0 @0=+     ]zip{{+}*                }:^%]\+}*0=^

अंतर:

  • प्रारंभिक ~इसलिए है क्योंकि यह स्निपेट के बजाय एक कार्यक्रम है।
  • [1.]की जगह 1क्या में परिवर्तन से मेल खाती है पर नज़र रखी है।
  • अतिरिक्त {(\{)}%+}%उस विभाजन में प्रत्येक तत्व को {1+}%बढ़ाता है , और विभाजन में जोड़ता 1है।
  • 0ट्रैक किए गए परिवर्तन के हिस्से के रूप में [0](गोल्फ के लिए 1,) हो जाता है , लेकिन क्योंकि यह एक सरणी रहने की जरूरत है जब एक दूसरे के लिए यह अतिरिक्त की जरूरत है [ ]
  • साधारण योग {+}*विभाजन से भारित चयन हो जाता है, उनकी गणना के योग के साथ संयुक्त।
  • (;`उत्पादन और पुट विभाजन एक अच्छा प्रारूप में से गिनती निकाल देता है।

परीक्षण की रूपरेखा

;7000,{;
  '5'

  ~[[[1.]]]\({..[[{{(\{)}%+}%1$,1$,-=}%[1,]@0=+{1+}%]zip{{(\.,/*~}%.,.rand@=+}:^%]\+}*0=^(;`

}%
:RESULTS
.&${
  RESULTS.[2$]--,' '\n
}/

यदि आप अलग-अलग संख्या में परीक्षण चलाना चाहते हैं, तो प्रारंभिक 7000 को घुमाएँ। ध्यान दें कि यह ऑनलाइन डेमो के लिए बहुत धीमी है।


3

जावा, 285 267 बाइट्स

int[][]p;void p(int n){p=new int[n+1][n+1];int a=n,b=k(n,a),c,d;for(b*=Math.random();n>0;System.out.print(c+" "),n-=a=c)for(c=0;c++<(a<n?a:n)&b>=(d=k(n-c,c));b-=d);}int k(int n,int k){if(p[n][k]<1)for(int a=0,b=0;b<k&b++<n;p[n][k]=a)a+=k(n-b,b);return n>0?p[n][k]:1;}

यह TheBestOne के उत्तर के समान विधि है, लेकिन यह नक्शे के बजाय एक सरल सरणी का उपयोग करता है। इसके अलावा, यादृच्छिक विभाजन को ए के रूप में वापस करने के बजाय List, यह उन्हें कंसोल पर प्रिंट करता है।

नीचे एक परीक्षण कार्यक्रम है जो इसे 100000 बार चलाता है। उदाहरण के लिए n=5, सभी सेट मेरे अंतिम रन पर एक परिपूर्ण 1/7 के 0.64% के भीतर थे।

public class Partition {
    public static void main(String[] args) {
        Partition p = new Partition();
        for(int i=0;i<100000;i++){
            p.p(5);
            System.out.println();
        }
    }

    int[][]p;

    void p(int n){
        p=new int[n+1][n+1];
        int a=n,b=k(n,a),c,d;
        for(b*=Math.random();n>0;System.out.print(c+" "),n-=a=c)
            for(c=0;c++<(a<n?a:n)&b>=(d=k(n-c,c));b-=d);
    }

    int k(int n,int k){
        if(p[n][k]<1)
            for(int a=0,b=0;b<k&b++<n;p[n][k]=a)
                a+=k(n-b,b);
        return n>0?p[n][k]:1;
    }

}

3
यद्यपि आप golfed गए हैं Math.minकरने के लिए नीचे कॉल (k<n?k:n)वह आपको पूरी तरह खुदाई और सिर्फ दो चेकों करके आगे जा सकते हैं: b<k&b++<n। तुम भी आसानी से कर सकते हैं खाई n>0पाश सशर्त का हिस्सा (के बाद से n>0&b<nकरने के लिए कम कर देता है b<nजब bगैर नकारात्मक गारंटी है)।
पीटर टेलर

@PeterTaylor साभार एक और रूप लेने से मुझे अतिरिक्त रिटर्न स्टेटमेंट से छुटकारा मिल जाता है और अलग intघोषणा भी।
जोबिट्स

3

सीजेएम, 64 56 बाइट्स

ri_L{_0>{\,f{)_@1$-j+}{)@)2$+:Umr@<@@?U+}*}{!a\;}?}2j);p

आप इस स्क्रिप्ट के साथ इसका परीक्षण कर सकते हैं:

ria100*{_L{_0>{\,f{)_@1$-j+}{)@)2$+:Umr@<@@?U+}*}{!a\;}?}2j);}%__|\f{_,\2$a-,-}2/p

व्याख्या

ri_                  " Read an integer and duplicate. ";
L{                   " Create a memoized function of the maximum and the sum, which returns
                       a random partition, and the total number of partitions as the last item. ";
    _0>              " If sum > 0: ";
    {
        \,f{         " For I in 0..max-1: ";
            )_@1$-   " Stack: I+1 I+1 sum-I-1 ";
            j+       " Recursively call with the two parameters, and prepend I+1. ";
        }
        {            " Reduce on the results: ";
            )@)2$+   " Stack: partition1 total1 partition2 total1+total2 ";
            :Umr     " U = total1+total2, then generate a random number smaller than that. ";
            @<@@?    " If it is <total1, choose partition1, else choose partition2. ";
            U+       " Append the total back to the array. ";
        }*
    }
    {!a\;}?          " Else return [0] if negative, or [1] if zero. ";
}2j
);p                  " Discard the total and print. ";

2
); आप अपने जवाब का गलत "नहीं golfed बहुत अच्छी तरह से" भाग को निकाल देना चाहिए
anatolyg

@anatolyg हटा दिया गया। लेकिन मेरा मानना ​​है कि अभी भी कुछ बाइट्स निकालना संभव है। मैं ऐसा करने के लिए बहुत आलसी हूँ।
jimmy23013

3

पायथ, 64 बाइट्स

Https://stackoverflow.com/a/2163753/4230423 का उपयोग करता है सिवाय इसके कि) कोई कैश नहीं है क्योंकि पायथ स्वचालित रूप से याद करता है, बी) सूची में जोड़ने के बजाय प्रत्येक प्रिंट करता है, और सी) पायथ के लिए अनुवादित है।

M?smg-Gddr1hhS,GHG1Akd,QOgQQWQFNr1hhS,QkKg-QNNI<dKB-=dK)N=kN-=QN

जब मेरे पास समय होगा, तो मैं इसका स्पष्टीकरण पोस्ट करूंगा, लेकिन यहां संबंधित अजगर कोड है:

g=lambda G,H: sum(map(lambda d:g(G-d, d), range(1, (H if H<G else G) + 1))) if G else 1
Q=input()
k,d = Q,random.randrange(g(Q, Q))
while Q:
    for N in range(1, min(k, Q) + 1):
        K = g(Q-N, N)
        if d < K:
            break
        d -= K
    print N
    k=N
    Q -= N

संपादित करें: अंत में मुझे स्पष्टीकरण करने के लिए मिला:

M                Lambda g(G,H)
 ?         G     If G truthy
  s              Sum
   m             Map
    g            Recursive call
     -Gdd        G-d,d
    r            Range
     1           1 to
     h           +1
      hS         First element of sorted (does min)
       ,GH       From G and H
   1             Else 1
A                Double assign
 kd              Vars k and d
 ,               To vals
  Q              Q (evaled input)
  O              Randrange 0 till val
   gQQ           Call g(Q, Q)
WQ               While Q is truthy
 FN              For N in
  r              Range
   1             From one
   h             Till +1
    hS,QK        Min(Q,K)
  Kg             K=g(
   -QN           Q-N
   N             N
  I<dK           If d<k
   B             Break (implicit close paren)
  -=dk           Subtracts d-=k
 )               Close out for loop
 N               Prints N
 =kN             Set k=N
 -=QN            Subtracts Q-=N

2

सप्तक, 200

function r=c(m)r=[];a=eye(m);a(:,1)=1;for(i=3:m)for(j=2:i-1)a(i,j)=a(i-1,j-1)+a(i-j,j);end;end;p=randi(sum(a(m,:)));while(m>0)b=a(m,:);c=cumsum(b);x=min(find(c>=p));r=[r x];p=p-c(x)+b(x);m=m-x;end;end

Ungolfed:

function r=c(m)
  r=[];
  a=eye(m);
  a(:,1)=1;
  for(i=3:m)
    for(j=2:i-1)
      a(i,j)=a(i-1,j-1)+a(i-j,j);
    end;
  end;
  p=randi(sum(a(m,:)));
  while(m>0)
    b=a(m,:);
    c=cumsum(b);
    x=min(find(cumsum(b)>=p));
    r=[r x];
    p=p-c(x)+b(x);
    m=m-x;
  end
end

एक वर्ग मैट्रिक्स का निर्माण करें जहां प्रत्येक कोशिका (m, n) उन संख्याओं के विभाजन को दर्शाती है mजिनकी सबसे बड़ी संख्या है n, नथ निकालने के अनुसार @ फैरसुम इसलिए कृपया उद्धृत किया गया है। उदाहरण के लिए, 5,2हमें 2 देता है क्योंकि दो वैध विभाजन हैं 2,2,1और 2,1,1,16,3हमें 3 देता है 3,1,1,1, 3,2,1और 3,3

अब हम निश्चित रूप से p'th विभाजन को ढूँढ सकते हैं। यहां, हम pएक यादृच्छिक संख्या के रूप में उत्पन्न कर रहे हैं, लेकिन आप स्क्रिप्ट को थोड़ा बदल सकते हैं इसलिए pयह एक पैरामीटर है:

function r=c(m,p)
  r=[];
  a=eye(m);
  a(:,1)=1;
  for(i=3:m)
    for(j=2:i-1)
      a(i,j)=a(i-1,j-1)+a(i-j,j);
    end;
  end;
  while(m>0)
    b=a(m,1:m);
    c=cumsum(b);
    x=min(find(c>=p));
    r=[r x];
    p=p-c(x)+b(x);
    m=m-x;
  end
end

अब हम यह निर्धारित कर सकते हैं कि प्रत्येक परिणाम पूरी तरह से p पर निर्भर है:

octave:99> for(i=1:7)
> c(5,i)
> end
ans =

   1   1   1   1   1

ans =

   2   1   1   1

ans =

   2   2   1

ans =

   3   1   1

ans =

   3   2

ans =

   4   1

ans =  5

इस प्रकार, मूल पर वापस जा रहा है जहां पी यादृच्छिक रूप से उत्पन्न होता है, हमें आश्वासन दिया जा सकता है कि प्रत्येक परिणाम समान रूप से होने की संभावना है।


मुझे आपके 5,2 उदाहरण के बारे में निश्चित नहीं है। दो विभाजन नहीं होने चाहिए (2,2,1)और (2,1,1,1,1)(चूंकि आपने जिन दो को सूचीबद्ध किया है उनकी संख्या इससे अधिक है 2)।
मार्टिन एंडर

आप ठीक कह रहे हैं, मुझे चीजें ठीक हो गई हैं। दो घटकों के साथ दो विभाजन होते हैं, और दो विभाजन शुरू होते हैं 2। मेरा मतलब बाद का था।
dcsohl 20

2

आर, 198 बाइट्स

function(m){r=c();a=diag(m);a[,1]=1;for(i in 3:m)for(j in 2:(i-1))a[i,j]=a[i-1,j-1]+a[i-j,j];p=sample(sum(a[m,]),1);while(m>0){b=a[m,];c=cumsum(b);x=min(which(c>=p));r=c(r,x);p=p-c[x]+b[x];m=m-x};r}

Ungolfed:

f <- function(m) {
    r <- c()
    a <- diag(m)
    a[, 1] <- 1
    for (i in 3:m)
        for (j in 2:(i-1))
            a[i, j] <- a[i-1, j-1] + a[i-j, j]
    p <- sample(sum(a[m, ]), 1)
    while (m > 0) {
        b <- a[m, ]
        c <- cumsum(b)
        x <- min(which(c >= p))
        r <- c(r, x)
        p <- p - c[x] + b[x]
        m <- m - x
    }
    return(r)
}

यह ऑक्टेव में @ dcsohl के महान समाधान के रूप में एक ही संरचना का अनुसरण करता है , और इस प्रकार यह @ Faersum द्वारा पोस्ट किए गए नूथ एक्सट्रैक्ट पर भी आधारित है ।

मैं इसे बाद में संपादित करूंगा यदि मैं आर में एक अधिक रचनात्मक समाधान के साथ आ सकता हूं। इस बीच, किसी भी इनपुट का निश्चित रूप से स्वागत है।


1

जावा, 392 बाइट्स

import java.util.*;Map a=new HashMap();List a(int b){List c=new ArrayList();int d=b,e=b(b,d),f=(int)(Math.random()*e),g,i;while(b>0){for(g=0;g++<Math.min(d, b);f-=i){i=b(b-g,g);if(f<i)break;}c.add(g);d=g;b-=g;}return c;}int b(int b,int c){if(b<1)return 1;List d=Arrays.asList(b,c);if(a.containsKey(d))return(int)a.get(d);int e,f;for(e=f=0;f++<Math.min(c, b);)e+=b(b-f,f);a.put(d,e);return e;}

के साथ बुलाओ a(n)। एक रिटर्न Listकी Integerरों

इंडेंट:

import java.util.*;

Map a=new HashMap();

List a(int b){
    List c=new ArrayList();
    int d=b,e=b(b,d),f=(int)(Math.random()*e),g,i;
    while(b>0){
        for(g=0;g++<Math.min(d, b);f-=i){
            i=b(b-g,g);
            if(f<i)
                break;
        }
        c.add(g);
        d=g;
        b-=g;
    }
    return c;
}

int b(int b,int c){
    if(b<1)
        return 1;
    List d=Arrays.asList(b,c);
    if(a.containsKey(d))
        return(int)a.get(d);
    int e,f;
    for(e=f=0;f++<Math.min(c, b);)
        e+=b(b-f,f);
    a.put(d,e);
    return e;
}

Https://stackoverflow.com/a/2163753/4230423 से अनुकूलित और गोल्फ

यह कैसे काम करता है: हम गणना कर सकते हैं कि पूर्णांक n के कितने विभाजन O ( n 2 ) समय में हैं। एक साइड इफेक्ट के रूप में, यह आकार O ( n 2 ) की एक तालिका का उत्पादन करता है जिसे हम O के ( n ) समय में, किसी भी पूर्णांक k के लिए n के k विभाजन को उत्पन्न करने के लिए उपयोग कर सकते हैं ।

तो कुल = विभाजन की संख्या दें । 0 से कुल में एक यादृच्छिक संख्या k चुनें - 1. k वें विभाजन उत्पन्न करें ।

हमेशा की तरह , सुझावों का स्वागत है :)


1

पायथन 2, 173 बाइट्स

from random import*
N,M=input__
R=67;d=[(0,[])]*R*R
for k in range(R*R):p,P=d[k+~R];q,Q=d[k-k%R*R];d[k]=p+q+0**k,[[x+1 for x in Q],[1]+P][random()*(p+q)<p]
print d[N*R+M][1]

रिकर्सिवली एक शब्दकोश बनाता है dकुंजी के साथ, kएक जोड़ी का प्रतिनिधित्व करने (n,m)से k=67*n+m(गारंटी का उपयोग कर n<=65)। प्रविष्टि भागों nमें विभाजन की संख्या का एक टपल है m, और एक यादृच्छिक ऐसा विभाजन। गणना को पुनरावर्ती सूत्र द्वारा गणना की जाती है (इसे इंगित करने के लिए फेर्सम के लिए धन्यवाद)

f(n,m) = f(n-1,m-1) + f(n,n-m),

और यादृच्छिक विभाजन इसकी गिनती के लिए आनुपातिक के साथ इसकी दो शाखाओं में से एक को चुनकर अद्यतन किया जाता है। अद्यतन को 1पहली शाखा के लिए जोड़कर और दूसरे के लिए हर तत्व को बढ़ाने के द्वारा किया जाता है ।

मुझे शून्य के मायने बताने mऔर nदेने के लिए बहुत परेशानी हो रही थी । सबसे पहले, मैंने एक डिक्शनरी का इस्तेमाल किया, जो 0 की गिनती और एक खाली सूची के लिए डिफॉल्ट करता है। यहां, मैं एक सूची का उपयोग कर रहा हूं और इसके बजाय इस डिफ़ॉल्ट प्रविष्टि के साथ पैडिंग कर रहा हूं। नकारात्मक सूचकांकों की वजह से सूची को उसके अंत से पढ़ा जा सकता है, जो डिफ़ॉल्ट प्रविष्टि देता है अंत तक कभी भी पास नहीं पहुंचता है, और रैपराउंड केवल एक क्षेत्र को स्पर्श करते हैं m>n


1

80386 मशीन कोड, 105 बाइट्स

कोड के Hexdump:

60 8b fa 81 ec 00 41 00 00 33 c0 8b f4 33 d2 42
89 14 06 42 33 ed 8b d8 03 2c 1e 2a fa 73 f9 83
c6 04 89 2c 06 42 3b d1 76 ea fe c4 3a e1 76 db
33 d2 0f c7 f0 f7 f5 86 e9 85 d2 74 1b 33 c0 8d
34 0c 39 14 86 77 03 40 eb f8 2b 54 86 fc 40 89
07 83 c7 04 2a e8 77 e1 42 89 17 83 c7 04 fe cd
7f f7 4a b6 41 03 e2 61 c3

एक सी फ़ंक्शन के रूप में void random_partition(int n, int result[]);:। यह आपूर्ति किए गए बफर में संख्याओं की सूची के रूप में परिणाम देता है; यह किसी भी तरह से सूची के अंत को चिह्नित नहीं करता है, लेकिन उपयोगकर्ता संख्याओं को जमा करके अंत की खोज कर सकता है - जब राशि बराबर होती है तो सूची समाप्त हो जाती है n

उपयोग कैसे करें (विजुअल स्टूडियो में):

#include <stdio.h>

__declspec(naked) void __fastcall random_partiton(int n, int result[])
{
#define a(byte) __asm _emit 0x ## byte
a(60) a(8b) a(fa) a(81) a(ec) a(00) a(41) a(00) a(00) a(33) a(c0) a(8b) a(f4) a(33) a(d2) a(42)
a(89) a(14) a(06) a(42) a(33) a(ed) a(8b) a(d8) a(03) a(2c) a(1e) a(2a) a(fa) a(73) a(f9) a(83)
a(c6) a(04) a(89) a(2c) a(06) a(42) a(3b) a(d1) a(76) a(ea) a(fe) a(c4) a(3a) a(e1) a(76) a(db)
a(33) a(d2) a(0f) a(c7) a(f0) a(f7) a(f5) a(86) a(e9) a(85) a(d2) a(74) a(1b) a(33) a(c0) a(8d)
a(34) a(0c) a(39) a(14) a(86) a(77) a(03) a(40) a(eb) a(f8) a(2b) a(54) a(86) a(fc) a(40) a(89)
a(07) a(83) a(c7) a(04) a(2a) a(e8) a(77) a(e1) a(42) a(89) a(17) a(83) a(c7) a(04) a(fe) a(cd)
a(7f) a(f7) a(4a) a(b6) a(41) a(03) a(e2) a(61) a(c3)
}

void make_stack() // see explanations about stack below
{
    volatile int temp[65 * 64];
    temp[0] = 999;
}

int main()
{
    int result[100], j = 0, n = 64, counter = n;
    make_stack(); // see explanations about stack below

    random_partiton(n, result);

    while (counter > 0)
    {
        printf("%d ", result[j]);
        counter -= result[j];
        ++j;
    }
    putchar('\n');
}

उदाहरण आउटपुट (n = 64 के साथ):

21 7 4 4 3 3 3 3 2 2 2 2 2 1 1 1 1 1 1

इसके लिए बहुत स्पष्टीकरण की आवश्यकता है ...

निश्चित रूप से मैंने एल्गोरिथ्म का उपयोग किया था जो बाकी सभी ने भी उपयोग किया था; जटिलता के बारे में आवश्यकता के साथ कोई विकल्प नहीं था। इसलिए मुझे एल्गोरिथ्म को बहुत समझाने की ज़रूरत नहीं है। वैसे भी:

मैं उन भागों f(n, m)के विभाजन की संख्या के आधार पर निरूपित करता हूं, जिनका nकोई बड़ा भाग नहीं है m। मैं उन्हें 2-डी सरणी (सी के रूप में घोषित f[65][64]) में संग्रहीत करता हूं , जहां पहला सूचकांक है n, और दूसरा m-1। मैंने तय किया कि समर्थन करना n=65बहुत मुश्किल था, इसलिए इसे छोड़ दिया ...

यहाँ C कोड है जो इस तालिका की गणना करता है:

#define MAX_M 64
int f[(MAX_M + 1) * MAX_M];
int* f2;
int c; // accumulates the numbers needed to calculate f(n, m)
int m;
int k; // f(k, m), for various values of k, are accumulated
int n1;

for (n1 = 0; n1 <= n; ++n1)
{
    f2 = f;
    f2[n1 * MAX_M] = 1;
    for (m = 2; m <= n; ++m)
    {
        c = 0;
        k = n1;
        while (k >= 0)
        {
            c += f2[k * MAX_M];
            k -= m;
        }
        ++f2;
        f2[n1 * MAX_M] = c;
    }
}

इस कोड में कुछ अस्पष्ट शैली है, इसलिए इसे आसानी से असेंबली भाषा में परिवर्तित किया जा सकता है। यह उन तत्वों की गणना करता है f(n, n), जो nतत्वों के विभाजन की संख्या है । जब यह कोड समाप्त हो जाता है, तो अस्थायी चर cमें आवश्यक संख्या होती है, जिसका उपयोग यादृच्छिक विभाजन का चयन करने के लिए किया जा सकता है:

int index = rand() % c;

बाद में, यह indexउत्पन्न तालिका का उपयोग करके आवश्यक प्रारूप (संख्याओं की सूची) में परिवर्तित हो जाता है।

do {
    if (index == 0)
        break;

    m = 0;
    f2 = &f[n * MAX_M];
    while (f2[m] <= index)
    {
        ++m;
    }

    index -= f2[m-1];
    ++m;
    *result++ = m;
    n -= m;
} while (n > 0);

do {
    *result++ = 1;
    --n;
} while (n > 0);

यह कोड असेंबली भाषा में रूपांतरण के लिए भी अनुकूलित है। एक छोटा "बग" है: यदि विभाजन 1में अंत में कोई संख्या नहीं है , तो अंतिम लूप का सामना होता है n = 0, और एक अनावश्यक 1तत्व को आउटपुट करता है। हालांकि, यह चोट नहीं करता है, क्योंकि मुद्रण कोड संख्या के योग को ट्रैक करता है, और इस बाहरी संख्या को प्रिंट नहीं करता है।

इनलाइन असेंबली में रूपांतरित होने पर, यह कोड इस तरह दिखता है:

__declspec(naked) void _fastcall random_partition_asm(int n, int result[])
{
    _asm {
        pushad;

        // ecx = n
        // edx = m
        // bh = k; ebx = k * MAX_M * sizeof(int)
        // ah = n1; eax = n1 * MAX_M * sizeof(int)
        // esp = f
        // ebp = c
        // esi = f2
        // edi = result

        mov edi, edx;
        sub esp, (MAX_M + 1) * MAX_M * 4; // allocate space for table
        xor eax, eax;
    row_loop:
        mov esi, esp;
        xor edx, edx;
        inc edx;
        mov dword ptr [esi + eax], edx;
        inc edx;

    col_loop:
        xor ebp, ebp;
        mov ebx, eax;

    sum_loop:
        add ebp, [esi + ebx];
        sub bh, dl;
        jae sum_loop;

        add esi, 4;
        mov [esi + eax], ebp;
        inc edx;
        cmp edx, ecx;
        jbe col_loop;

        inc ah;
        cmp ah, cl;
        jbe row_loop;

        // Done calculating the table

        // ch = n; ecx = n * MAX_M * sizeof(int)
        // eax = m
        // ebx = 
        // edx = index
        // esp = f
        // esi = f2
        // ebp = c
        // edi = result

        xor edx, edx;
        rdrand eax; // generate a random number
        div ebp; // generate a random index in the needed range
        xchg ch, cl; // multiply by 256

    n_loop:
        test edx, edx;
        jz out_trailing;
        xor eax, eax;
        lea esi, [esp + ecx];

    m_loop:
        cmp [esi + eax * 4], edx;
        ja m_loop_done;
        inc eax;
        jmp m_loop;
    m_loop_done:

        sub edx, [esi + eax * 4 - 4];
        inc eax;
        mov [edi], eax;
        add edi, 4;
        sub ch, al;
        ja n_loop;

    out_trailing:
        inc edx;
    out_trailing_loop:
        mov dword ptr [edi], edx;
        add edi, 4;
        dec ch;
        jg out_trailing_loop;

        dec edx;
        mov dh, (MAX_M + 1) * MAX_M * 4 / 256;
        add esp, edx;
        popad;
        ret;
    }
}

ध्यान देने योग्य कुछ मजेदार बातें:

  • एक यादृच्छिक संख्या उत्पन्न करना मशीन कोड ( rdrandनिर्देश) के सिर्फ 3 बाइट्स लेता है
  • एक संयोग से, तालिका का आकार 64 है, इसलिए एक पंक्ति का आकार 256 बाइट्स है। मैं "हाई-बाइट" रजिस्टरों में पंक्ति सूचकांकों को रखने के लिए इसका उपयोग करता हूं ah, जो मुझे 256 से स्वचालित गुणा देता है। इसका लाभ उठाने के लिए, मैंने इसके लिए समर्थन का त्याग किया n = 65। मुझे उम्मीद है कि मुझे इस पाप के लिए माफ किया जा सकता है ...
  • स्टैक पर जगह का आवंटन स्टैक पॉइंटर रजिस्टर से 0x4100 घटाकर किया जाता है esp। यह एक 6-बाइट अनुदेश है! इस नंबर को वापस जोड़ने पर, मैं इसे 5 बाइट्स में करने में कामयाब रहा:

        dec edx; // here edx = 1 from earlier calculations
        mov dh, (MAX_M + 1) * MAX_M * 4 / 256; // now edx = 0x4100
        add esp, edx; // this deallocates space on stack
    
  • MS Visual Studio में इस फ़ंक्शन को डीबग करते समय, मुझे पता चला कि यह उस स्थान पर डेटा लिखते समय क्रैश हो जाता है जिसे उसने स्टैक पर आवंटित किया था! कुछ खुदाई के बाद, मैंने कुछ प्रकार के स्टैक ओवररन प्रोटेक्शन की खोज की: ओएस स्टैक के लिए वर्चुअल पतों की एक बहुत ही सीमित सीमा आवंटित करता है; यदि कोई फ़ंक्शन बहुत दूर तक एक पते तक पहुंचता है, तो OS मानता है कि यह ओवररन है और प्रोग्राम को मारता है। हालांकि, यदि किसी फ़ंक्शन में कई स्थानीय चर हैं, तो ओएस इसे काम करने के लिए कुछ अतिरिक्त "जादू" करता है। इसलिए मुझे एक खाली फ़ंक्शन को कॉल करना होगा जिसमें स्टैक पर एक बड़ा सरणी आवंटित किया गया है। इस फ़ंक्शन के बाद, अतिरिक्त स्टैक VM पृष्ठ आवंटित किए जाते हैं और उनका उपयोग किया जा सकता है।

        void make_stack()
        {
            volatile int temp[65 * 64];
            temp[0] = 999; // have to "use" the array to prevent optimizing it out
        }
    
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.