एक क्रमचय का पुनर्निर्माण करें


16

परिचय

मान लीजिए कि आपको nवस्तुओं का यादृच्छिक क्रमांकन सौंपा गया है । क्रमचय को एक बॉक्स में सील कर दिया जाता है, इसलिए आपको पता नहीं है कि यह कौन n!सा संभावित है। यदि आप nअलग-अलग वस्तुओं में क्रमपरिवर्तन को लागू करने में कामयाब रहे , तो आप तुरंत इसकी पहचान को कम कर सकते हैं। हालाँकि, आपको केवल लंबाई- nबाइनरी वैक्टर के लिए क्रमपरिवर्तन लागू करने की अनुमति है , जिसका अर्थ है कि आपको इसे पहचानने के लिए कई बार इसे लागू करना होगा। स्पष्ट रूप से, इसे nकेवल एक 1ही काम के साथ वैक्टर पर लागू करना है , लेकिन यदि आप चतुर हैं, तो आप इसे log(n)अनुप्रयोगों के साथ कर सकते हैं । उस पद्धति का कोड लंबा होगा, हालांकि ...

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

काम

आपका कार्य एक नामित फ़ंक्शन (या निकटतम समतुल्य) लिखना है जो fइनपुट के रूप में एक सकारात्मक पूर्णांक लेता है n, और 0-आधारित या 1-आधारित इंडेक्सिंग का उपयोग करते हुए pपहले nपूर्णांकों का एक क्रमांकन । इसका आउटपुट पर्मुटेशन है p। हालांकि, आपको pसीधे क्रमपरिवर्तन तक पहुंचने की अनुमति नहीं है । केवल एक चीज जो आप इसके साथ कर सकते हैं वह है इसे nबिट्स के किसी भी वेक्टर पर लागू करना । इस प्रयोजन के लिए, आप एक सहायक फ़ंक्शन का उपयोग करेंगे Pजो एक क्रमपरिवर्तन pऔर बिट्स के वेक्टर में होता है v, और अनुमत वेक्टर को वापस लौटाता है, जिनके p[i]वें समन्वय में बिट शामिल होता है v[i]। उदाहरण के लिए:

P([1,2,3,4,0], [1,1,0,0,0]) == [0,1,1,0,0]

आप इस तरह के रूप में किसी भी दो अलग-अलग मान, के साथ "बिट्स" की जगह ले सकता 3है और -4, या 'a'और 'b'ताकि आप कॉल कर सकते हैं, और वे तय करने की आवश्यकता नहीं, Pदोनों के साथ [-4,3,3,-4]और [2,2,2,1]एक ही कॉल में f। की परिभाषा को Pआपके स्कोर की ओर नहीं गिना जाता है।

स्कोरिंग

किसी दिए गए इनपुट पर आपके समाधान की क्वेरी जटिलता सहायक फ़ंक्शन को कॉल करने की संख्या है P। इस उपाय को अस्पष्ट बनाने के लिए, आपका समाधान निर्धारक होना चाहिए। आप छद्म-बेतरतीब ढंग से उत्पन्न संख्याओं का उपयोग कर सकते हैं, लेकिन फिर आपको जनरेटर के लिए प्रारंभिक बीज को भी ठीक करना होगा।

में इस भंडार आप एक फ़ाइल बुलाया मिल जाएगा permutations.txtकि 505 क्रमपरिवर्तन, 50 और 150 के बीच समावेशी प्रत्येक लंबाई के 5, 0-आधारित अनुक्रमण (1 आधारित मामले में प्रत्येक की संख्या को बढ़ाना) का उपयोग होता है। प्रत्येक क्रमपरिवर्तन अपनी लाइन पर है, और इसके नंबर रिक्त स्थान से अलग किए गए हैं। आपका स्कोर इन इनपुट्स पर + औसत क्वेरी जटिलता की बाइट काउंट हैf । सबसे कम स्कोर जीतता है।

अतिरिक्त नियम

स्पष्टीकरण के साथ कोड पसंद किया जाता है, और मानक खामियों को रोक दिया जाता है। विशेष रूप से, व्यक्तिगत बिट अप्रभेद्य होते हैं (इसलिए आप Integerवस्तुओं का वेक्टर नहीं दे सकते हैं Pऔर उनकी पहचान की तुलना कर सकते हैं), और फ़ंक्शन Pहमेशा अपने इनपुट को फिर से व्यवस्थित करने के बजाय एक नया वेक्टर लौटाता है। आप स्वतंत्र रूप से fऔर के नाम बदल सकते हैं P, और जिस क्रम में वे अपने तर्क लेते हैं।

यदि आप अपनी प्रोग्रामिंग भाषा में जवाब देने वाले पहले व्यक्ति हैं, तो आपको एक परीक्षण हार्नेस को शामिल करने के लिए दृढ़ता से प्रोत्साहित किया जाता है, जिसमें फ़ंक्शन का कार्यान्वयन Pभी शामिल है जो उस समय की संख्या को भी गिना जाता है जिसे यह कहा जाता था। एक उदाहरण के रूप में, यहाँ पायथन 3 के लिए हार्नेस है।

def f(n,p):
    pass # Your submission goes here

num_calls = 0

def P(permutation, bit_vector):
    global num_calls
    num_calls += 1
    permuted_vector = [0]*len(bit_vector)
    for i in range(len(bit_vector)):
        permuted_vector[permutation[i]] = bit_vector[i]
    return permuted_vector

num_lines = 0
file_stream = open("permutations.txt")
for line in file_stream:
    num_lines += 1
    perm = [int(n) for n in line.split()]
    guess = f(len(perm), perm)
    if guess != perm:
        print("Wrong output\n %s\n given for input\n %s"%(str(guess), str(perm)))
        break
else:
    print("Done. Average query complexity: %g"%(num_calls/num_lines,))
file_stream.close()

कुछ भाषाओं में, इस तरह के हार्नेस को लिखना असंभव है। सबसे विशेष रूप से, हास्केल शुद्ध फ़ंक्शन Pको उस समय की संख्या को रिकॉर्ड करने की अनुमति नहीं देता है जिसे यह कहा जाता है। इस कारण से, आपको अपने समाधान को इस तरह से फिर से लागू करने की अनुमति है कि यह इसकी क्वेरी जटिलता की गणना भी करे और दोहन में इसका उपयोग करें।


हम के रूप में, उदाहरण के लिए "दो अलग-अलग वस्तुओं के वेक्टर" "बिट्स के वेक्टर" व्याख्या कर सकते हैं, इस परिभाषा के तहत दोनों abaaabababaaऔर -4 3 3 3 -4 3बिट्स की एक वेक्टर होगा।
फ़ूजक्कल

@FUZxxl हां, जब तक कि व्यक्तिगत आइटम अप्रभेद्य हैं।
जरगब

मेरे पास कार्यान्वयन दृष्टिकोण में वे नंबर हैं।
फूजएक्सएक्सएल

@FUZxxl मैंने कल्पना को संपादित किया।
जरगब

जवाबों:


11

जे, 44.0693 22.0693 = 37 15 + 7.06931

अगर हम फोन नहीं कर सकते हैं Pपर i. n, हम कम से कम कॉल पर कर सकते हैं Pके प्रत्येक बिट पर i. nअलग से। के आह्वान की संख्या Pहै >. 2 ^. n(oflog 2 n ations)। मेरा मानना ​​है कि यह इष्टतम है।

f=:P&.|:&.#:@i.

यहां फ़ंक्शन का कार्यान्वयन है Pजो क्रमचय वेक्टर का उपयोग करता है pऔर इनवोकेशन की संख्या को बचाता है Pinv

P =: 3 : 0"1
 Pinv =: Pinv + 1
 assert 3 > # ~. y    NB. make sure y is binary
 p { y
)

यहाँ एक परीक्षण दोहन है जो क्रमचय प्राप्त करता है और इसके चालान की संख्या लौटाता है p:

harness =: 3 : 0
 Pinv =: 0
 p =: y
 assert y = f # y     NB. make sure f computed the right permutation
 Pinv
)

और यहाँ है कि आप इसे फाइल पर कैसे उपयोग कर सकते हैं permutations.txt:

NB. average P invocation count
(+/ % #) harness@".;._2 fread 'permutations.txt'

व्याख्या

लघु व्याख्या पहले से ही ऊपर दी गई है, लेकिन यहां एक अधिक विस्तृत है। सबसे पहले, fरिक्त स्थान के साथ और एक स्पष्ट कार्य के रूप में:

f =: P&.|:&.#:@i.
f =: 3 : 'P&.|:&.#: i. y'

पढ़ें:

चलो पहले के आधार -2 प्रतिनिधित्व के तहत स्थानांतरण के तहत किया पी वाई पूर्णांकों।

जहां y , f का औपचारिक पैरामीटर है जे में, पैरामीटर (a) फ़ंक्शन को x और y कहा जाता है यदि क्रिया डायडिक है (दो पैरामीटर हैं) और y यदि यह मोनैडिक है (एक पैरामीटर है)।

लागू करने के बजाय Pपर i. n(यानी 0 1 2 ... (n - 1)), हम आह्वान Pमें संख्या के प्रत्येक बिट स्थिति पर i. n। एक ही तरीके से सभी क्रमपरिवर्तन की अनुमति के बाद से, हम क्रमिक क्रमबद्धता प्राप्त करने के लिए क्रमांकित बिट्स को संख्याओं में फिर से इकट्ठा कर सकते हैं:

  • i. y- से पूर्णांकों 0के लिए y - 1
  • #: y- yआधार में प्रतिनिधित्व 2. यह प्राकृतिक तरीके से संख्याओं के वैक्टर तक बढ़ाया जाता है। उदाहरण के लिए, #: i. 16पैदावार:

    0 0 0 0
    0 0 0 1
    0 0 1 0
    0 0 1 1
    0 1 0 0
    0 1 0 1
    0 1 1 0
    0 1 1 1
    1 0 0 0
    1 0 0 1
    1 0 1 0
    1 0 1 1
    1 1 0 0
    1 1 0 1
    1 1 1 0
    1 1 1 1
    
  • #. y- yआधार 2 नंबर के रूप में व्याख्या की गई। विशेष रूप से, यह प्रतिलोम है #:; y ~: #. #:हमेशा रखती है।

  • |: y- yप्रत्यारोपित।
  • u&.v y- के uतहत v, यह वह vinv u v yजगह vinvहै जहां उलटा है v। ध्यान दें कि |:इसका अपना विलोम है।

  • P y- फ़ंक्शन परिभाषा के अनुसार Pप्रत्येक वेक्टर पर लागू होता है y


3

पायथ 32 + 7.06931 = 37.06931

मैंने निम्नलिखित एल्गोरिथ्म को पूरी तरह से स्वतंत्र पाया। लेकिन यह कमोबेश उसी तरह है जैसे कि फूज़ेक्नल बहुत छोटा जे समाधान (जहाँ तक मैं इसे समझता हूँ)।

पहले फ़ंक्शन की परिभाषा P, जो एक अज्ञात क्रमपरिवर्तन के अनुसार थोड़ा-सरणी की अनुमति देता है।

D%GHJHVJ XJ@HN@GN)RJ

और फिर कोड, जो क्रमचय निर्धारित करता है।

Mmxmi_mbk2Cm%dHCm+_jk2*sltG]0GdG

यह एक फ़ंक्शन को परिभाषित करता है g , जिसमें दो तर्क होते हैं। आप इसके द्वारा कॉल कर सकते हैं g5[4 2 1 3 0। यहाँ एक ऑनलाइन प्रदर्शन है । इतने (5) नेस्टेड मैप्स का कभी इस्तेमाल नहीं किया।

Btw मैं वास्तव में एक परीक्षण दोहन नहीं किया है। न ही कार्य करता हैP गिनता है कि मैं इसे कितनी बार कॉल करता हूं। मैं पहले से ही एल्गोरिथ्म का पता लगाने के लिए बहुत समय खर्च कर चुका हूं। लेकिन अगर आप मेरी व्याख्या पढ़ते हैं, तो यह स्पष्ट है कि यह int(log2(n-1)) + 1कॉल ( = ceil(log2(n))) का उपयोग करता है । और sum(int(log2(n-1)) + 1 for n in range(50, 151)) / 101.0 = 7.069306930693069

स्पष्टीकरण:

मैं वास्तव में इस एल्गोरिथ्म को खोजने में काफी कठिन समय था। यह मेरे लिए बिल्कुल भी स्पष्ट नहीं था कि कैसे हासिल किया जाएlog(n) । इसलिए मैंने छोटे से कुछ प्रयोग करने शुरू कर दिए n

पहला ध्यान दें: एक बिट-सरणी पूरक बिट-सरणी के समान जानकारी एकत्र करता है। इसलिए मेरे समाधान में सभी बिट-सरणियां सबसे अधिक हैंn/2 सक्रिय बिट है।

n = 3:

चूंकि हम केवल 1-सक्रिय बिट के साथ बिट-एरे का उपयोग कर सकते हैं, इष्टतम समाधान दो कॉल पर निर्भर करता है। जैसे P([1, 0, 0])औरP([0, 1, 0]) । परिणाम हमें पहले और दूसरे क्रमांक की संख्या बताते हैं, अप्रत्यक्ष रूप से हमें तीसरा नंबर मिलता है।

n = 4:

यहाँ यह थोड़ा दिलचस्प हो जाता है। अब हम दो प्रकार के बिट-सरणी का उपयोग कर सकते हैं। 1 सक्रिय बिट वाले और 2 सक्रिय बिट्स वाले। यदि हम एक सक्रिय बिट के साथ एक बिट-ऐरे का उपयोग करते हैं, तो हम केवल एक नंबर के क्रमांकन के बारे में जानकारी इकट्ठा करते हैं, और वापस आते हैं n = 3, जिसके परिणामस्वरूप 1 + 2 = 3कॉल आती हैं P। दिलचस्प बात यह है कि हम केवल 2 कॉल के साथ ही काम कर सकते हैं, अगर हम 2-सक्रिय बिट्स के साथ बिट-एरेज़ का उपयोग करते हैं। जैसे P([1, 1, 0, 0])और P([1, 0, 1, 0])

चलो हम आउटपुट मिलता कहना [1, 0, 0, 1]और [0, 0, 1, 1]। हम देखते हैं, कि बिट संख्या 4 आउटपुट सरणियों में सक्रिय है। एकमात्र बिट जो दोनों इनपुट सरणियों में सक्रिय था बिट नंबर 1 था, इसलिए स्पष्ट रूप से क्रमपरिवर्तन के साथ शुरू होता है 4। अब यह देखना आसान है, कि बिट 2 को बिट 1 (पहला आउटपुट) में स्थानांतरित कर दिया गया, और बिट 3 को बिट 3 (दूसरा आउटपुट) में स्थानांतरित कर दिया गया। इसलिए क्रमचय अवश्य होना चाहिए [4, 1, 3, 2]

n = 7:

अब कुछ बड़ा। मैं Pतुरंत कॉल दिखाता हूँ । वे एक बार हैं, कि मैं थोड़ी सोच और प्रयोग करने के बाद आया हूं। (ध्यान दें ये वे नहीं हैं, जो मैं अपने कोड में उपयोग करता हूं।)

P([1, 1, 1, 0, 0, 0, 0])
P([1, 0, 0, 1, 1, 0, 0])
P([0, 0, 1, 1, 0, 1, 0])

यदि पहले दो आउटपुट सरणियों में (और तीसरे में नहीं) बिट 2 सक्रिय है, तो हम जानते हैं कि क्रमचय बिट 1 से बिट 2 तक चलता है, क्योंकि बिट केवल एक ही बिट है जो पहले दो इनपुट सरणियों में सक्रिय है।

महत्वपूर्ण बात यह है कि, (प्रत्येक मैट्रिक्स के रूप में आदानों की व्याख्या) प्रत्येक स्तंभ अद्वितीय हैं। यह मुझे हेमिंग कोड पर याद आया , जहां एक ही चीज पूरी होती है। वे बस संख्या 1 से 7 लेते हैं, और कॉलम के रूप में अपने बिट-प्रतिनिधित्व का उपयोग करते हैं। मैं नंबर 0 से 6. का उपयोग करूंगा। अब अच्छा हिस्सा है, हम आउटपुट (फिर से कॉलम) को फिर से नंबर के रूप में व्याख्या कर सकते हैं। ये हमें लागू किए गए क्रमपरिवर्तन का परिणाम बताते हैं [0, 1, 2, 3, 4, 5, 6]

   0  1  2  3  4  5  6      1  3  6  4  5  0  2
P([0, 1, 0, 1, 0, 1, 0]) = [1, 1, 0, 0, 1, 0, 0]
P([0, 0, 1, 1, 0, 0, 1]) = [0, 1, 1, 0, 0, 0, 1]
P([0, 0, 0, 0, 1, 1, 1]) = [0, 0, 1, 1, 1, 0, 0]

इसलिए हमें केवल संख्याओं का पता लगाना है। बिट ० बिट ५ में समाप्त हो गया, बिट १ बिट ० में समाप्त हुआ, बिट २ बिट ६ में समाप्त हुआ, ... तो क्रमपरिवर्तन था [5, 0, 6, 1, 3, 4, 2]

Mmxmi_mbk2Cm%dHCm+_jk2*sltG]0GdG
M                                 define a function g(G, H), that will return
                                  the result of the following computation:
                                  G is n, and H is the permutation. 
                m            G     map each k in [0, 1, ..., Q-1] to:
                  _                   their inverse
                   jk2                binary representation (list of 1s and 0s)
                 +                    extended with 
                      *sltG]0         int(log2(Q - 1)) zeros
               C                   transpose matrix # rows that are longer 
                                                   # than others are shortened
           m%dH                    map each row (former column) d of 
                                   the matrix to the function P (here %)
          C                        transpose back
   m                              map each row k to:                         
    i    2                           the decimal number of the 
     _mbk                            inverse list(k) # C returns tuple :-(
Let's call the result X.  
 m                             G   map each d in [0, 1, ..., Q - 1] to:
  x         X                 d       the index of d in X

और क्रमपरिवर्तन समारोह के लिए कोड:

D%GHJHVJ XJ@HN@GN)RJ
D%GH                     def %(G, H):  # the function is called %
    JH                     J = copy(H)
      VJ         )        for N in [0, 1, ..., len(J) - 1]: 
         XJ@HN@GN            J[H[N]] = G[N]           
                  RJ      return J

1
यदि आप *sltQ]0साथ बदलते हैं m0sltQ, तो आपके पास समान लंबाई में 6 नेस्टेड मानचित्र हो सकते हैं।
isaacg

आपको चुनौती के अनुसार, अपना कोड असाइन करना चाहिए जो चुनौती को एक फ़ंक्शन को आदर्श रूप से नामित करता है, fहालांकि अन्य नामों की अनुमति है। असाइनमेंट आपके स्कोर की ओर मायने रखता है।
फ़ूजक्कल

@FUZxxl ने मेरा कोड अपडेट किया। अब gSTDIN से पढ़ने के बजाय एक फ़ंक्शन को परिभाषित करता है ।
जकुबे

2

गणितज्ञ, 63 + 100 = 163

मैं एक-आधारित क्रमपरिवर्तन का उपयोग कर रहा हूं, क्योंकि मैथमेटिका में अनुक्रमण काम करता है।

सबसे पहले, परीक्षण दोहन। यह क्वेरी फ़ंक्शन p(उपयोगकर्ता-परिभाषित नाम Mathematica में ऊपरी-मामला नहीं होना चाहिए):

p[perm_, vec_] := (
   i += 1;
   vec[[Ordering@perm]]
   );

और टेस्ट लूप के साथ इनपुट तैयारी:

permutations = 
  ToExpression@StringSplit@# + 1 & /@ 
   StringSplit[Import[
     "https://raw.githubusercontent.com/iatorm/permutations/master/permutations.txt"
   ], "\n"];
total = 0;
(
    i = 0;
    result = f@#;
    If[# != result, 
      Print["Wrong result for ", #, ". Returned ," result ", instead."]
    ];
    total += i;
    ) & /@ permutations;
N[total/Length@permutations]

और अंत में, मेरा वास्तविक सबमिशन जो अब के लिए भोली एल्गोरिथ्म का उपयोग करता है:

f=(v=0q;v[[#]]=1;Position[q~p~v,1][[1,1]])&/@Range@Length[q=#]&

या इंडेंटेशन के साथ:

f = (
     v = 0 q;
     v[[#]] = 1;
     Position[q~p~v, 1][[1, 1]]
) & /@ Range@Length[q = #] &
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.