2 नंबर को बार-बार जोड़कर कोई भी संख्या बनाएं


14

आपको दो 16-बिट रजिस्टर के साथ एक मशीन दी जाती है, xऔर y। रजिस्टरों प्रारंभ कर रहे हैं x=1और y=0। एकमात्र ऑपरेशन जो मशीन कर सकती है वह मोडुलो 65536 है।

  • x+=y- xद्वारा प्रतिस्थापित किया जाता है (x + y) mod 65536; yअपरिवर्तित है
  • y+=x - इसी तरह के लिए y
  • x+=x- xद्वारा प्रतिस्थापित किया जाता है 2x mod 65536; xभले ही कानूनी हो
  • y+=y - इसी तरह के लिए y

लक्ष्य (या तो रजिस्टरों में से एक में एक पूर्व निर्धारित संख्या में प्राप्त करने के लिए है xया y)।

एक प्रोग्राम या एक सबरूटीन लिखें जो एक नंबर (इन stdin, argvफंक्शन पैरामीटर, स्टैक या किसी अन्य पारंपरिक स्थान के ऊपर) प्राप्त करता है, और इस नंबर को प्राप्त करने के लिए एक प्रोग्राम को आउटपुट करता है। आउटपुट को किसी अन्य पारंपरिक आउटपुट डिवाइस पर जाना चाहिए stdout, या (यदि आपकी भाषा में कोई नहीं है stdout)।

आउटपुट प्रोग्राम इष्टतम से 100% प्लस 2 चरणों तक हो सकता है। यही है, यदि लक्ष्य संख्या प्राप्त करने के लिए सबसे कम कार्यक्रम में nकदम हैं, तो आपका समाधान इससे अधिक लंबा नहीं हो सकता है 2n+2। यह प्रतिबंध "बहुत आसान" समाधानों से बचने के लिए है (जैसे 1, 2, 3, ... की गिनती) लेकिन पूर्ण अनुकूलन की आवश्यकता नहीं है; मुझे उम्मीद है कि सबसे छोटा कार्यक्रम सबसे आसान है, लेकिन यह सुनिश्चित नहीं किया जा सकता ...

उदाहरण के लिए: इनपुट = 25. आउटपुट:

y+=x
x+=y
x+=y
x+=x
x+=x
x+=x
y+=x

एक और उदाहरण: किसी भी संख्या के लिए, आउटपुट में यह वैकल्पिक पैटर्न है। इनपुट = 21 के लिए, आउटपुट है

y+=x
x+=y
y+=x
x+=y
y+=x
x+=y
y+=x

सबसे छोटा कोड (बाइट्स में मापा गया) जीतता है।

(यह पहेली 16-बिट प्रोसेसर के लिए कुछ कोड से प्रेरित थी जिसे मुझे हाल ही में उत्पन्न करना था)

पीएस मुझे आश्चर्य है - किस कार्यक्रम के लिए इष्टतम कार्यक्रम सबसे लंबा है?


9
जिज्ञासा से बाहर, x+=xकानूनी ही क्यों अगर xयह भी है? इसके अलावा सबसे छोटे कार्यक्रम के लिए मुझे लगता है कि BFS काम कर सकता है।
Sp3000

लक्ष्य पर पहुंचने के बाद, कोई अगले लक्ष्य नंबर पर जा सकता है; किसी भी लक्ष्य को प्राप्त करने के लिए भयावहता के लिए, संख्याओं में से एक को विषम होना चाहिए। मैं अनावश्यक जटिलता से बचने के लिए लक्ष्य की एक अंतहीन धारा नहीं बनाना चाहता था, लेकिन आत्मा को इस तरह की धारा की अनुमति है ...
अनातोली

मैंने चरणों की संख्या पर प्रतिबंध को बदल दिया है, इसलिए लक्ष्य संख्या 0 या 1 के लिए आउटपुट प्रोग्राम को खाली होने की आवश्यकता नहीं है।
अनातोलीग डेस

3
यदि x+=xकेवल xएस के लिए भी काम करता है, तो 25 युगल 3 के इनपुट के लिए उदाहरण कैसे आया?
bcsb1001

जवाबों:


2

सीजेम, 31

जैसा @Tobia के जवाब, मेरे एल्गोरिथ्म भी बेशर्म है चोरी से प्रेरित @CChak रों जवाब '। लेकिन, काला जादू जो कि सीजेएम है, को बनाए रखते हुए, मैं एल्गोरिथ्म के एक छोटे से कार्यान्वयन को बनाने में कामयाब रहा।

इसे यहाँ आज़माएँ।

golfed:

qi{_4%!:X)/X!-'xX+"
y+="@}h;]W%`

Ungolfed:

qi          "Read input and convert to integer.";
{           "Do...";
  _4%!:X    "Assign (value mod 4 == 0) to X.";
  )/X!-     "If X, divide value by 2. If not X, decrement value.";
  'xX+      "If X, put 'y' on the stack. If not X, put 'x' on the stack.";
  "
y+="        "Put '\ny+=' on the stack.";
  @         "Rotate top 3 elements of stack left so the value is on top.";
}h          "... while value is not zero.";
;           "Discard zero value on stack.";
]W%         "Collect stack into array and reverse.";

कृपया मुझे सही करें अगर मैं गलत हूं, लेकिन मेरा मानना ​​था कि एक समान एल्गोरिथ्म के साथ जवाब में इस्तेमाल किया जाने वाला मॉडुलो 65536 ऑपरेशन अनावश्यक है। मैंने इस सवाल की व्याख्या की कि हम यह मान सकते हैं कि इनपुट एक मान्य अहस्ताक्षरित 16-बिट पूर्णांक होगा, और इस एल्गोरिथम के किसी भी मध्यवर्ती मान या परिणाम भी होंगे।


मॉड 65536 को हटाने पर एक दिलचस्प बिंदु। मुझे लगता है कि आप एक अच्छा मामला बनाते हैं कि "पूर्व निर्धारित संख्या" 0-65535 के भीतर होनी चाहिए।
सीसीहक

8

पर्ल 107 97

पहली पोस्ट, तो यहाँ जाता है।

sub h{($i)=@_;return if(($i%=65536)==0);($i%4==0)?do{h($i/2);say"y+=y";}:do{h($i-1);say"y+=x";}}

जो सभी रजिस्टर जोड़ मापदंड में फिट बैठता है, लेकिन मैंने यह देखने के लिए एक विस्तृत जांच नहीं की कि क्या मेरा उत्तर हमेशा चरणों की इष्टतम संख्या 2n + 2 के भीतर था। यह हर फाइबोनैचि संख्या के लिए सीमा के अंदर अच्छी तरह से है, हालांकि।

यहां एक अधिक विस्तृत ब्रेकडाउन है

sub h{                           # Declare the subroutine, it should be called referencing an integer value
   ($i)=@_;                      # Assign the i variable to the integer used in the call
   return if(($i%=65536)==0);    # Check for base condition of called by 0, and enforce modulo from the start.
   ($i%4==0) ?                   # If the value passed is even, and will result in an even number if we halve it
   do{h($i/2);say"y+=y";}        # Then do so and recurse 
   :do{h($i-1);say"y+=x";}       # Otherwise "subtract one" and recurse
}                                # Note that the print statements get called in reverse order as we exit.

जैसा कि मैंने उल्लेख किया है, यह गोल्फ में मेरा पहला प्रयास है, इसलिए मुझे यकीन है कि इस पर सुधार किया जा सकता है। इसके अलावा, मुझे यकीन नहीं है कि अगर शुरुआती सबरूटिन कॉल को एक पुनरावर्ती कॉल में गिना जाना है या नहीं, जो हमें कुछ चार्ट चला सकता है।

दिलचस्प रूप से हम कोड को 11 बाइट्स * से कम कर सकते हैं और रजिस्टर संचालन की संख्या के संदर्भ में हमारी "दक्षता" में सुधार कर सकते हैं, इस आवश्यकता को आराम करते हुए कि केवल मूल्य भी "दोगुना" हो सकते हैं। मैंने इसे यहाँ मज़े के लिए शामिल किया है:

sub h{($i)=@_;return if(($i%=65536)==0);($i%2==0)?do{h($i/2);say"y+=y";}:do{h($i-1);say"y+=x";}}

आरंभ परिशिष्ट:

वास्तव में इस समस्या को पसंद किया है, और मैं पिछले कुछ हफ्तों से इसे बंद कर रहा हूं। सोचा कि मैं अपने परिणाम पोस्ट करूंगा।

कुछ नंबर:

एक इष्टतम समाधान खोजने के लिए बीएफएस एल्गोरिथ्म का उपयोग करना, पहले 2 ^ 16 नंबरों में केवल 18 संख्याएं हैं जिनके लिए 23 चरणों की आवश्यकता होती है। वे हैं: 58558, 59894, 60110, 61182, 61278, 62295, 62430, 62910, 63422, 63462, 63979, 64230, 64314, 4486, 64510, 64698, 64854, 65295।

ऊपर वर्णित पुनरावर्ती एल्गोरिदम का उपयोग करते हुए, 45 ऑपरेशन में "सबसे कठिन" संख्या 65535 तक पहुंचने के लिए है। (६५५३४ में ४४ लगते हैं, और १४ संख्याएँ हैं जो ४३ कदम उठाती हैं) ६५५३५ भी इष्टतम से सबसे बड़ा प्रस्थान है, ४५ बनाम २२। २३ चरण का अंतर २ एन +१ है। (केवल तीन संख्याएँ 2n: 65534, 32767, 32751 को मारती हैं।) परिभाषित सीमा से अधिक तुच्छ (शून्य-चरण) मामलों को छोड़कर, पुनरावर्ती विधि औसतन लगभग 1.4 गुना इष्टतम समाधान है।

नीचे पंक्ति: 1-2 ^ 16 की संख्या के लिए, पुनरावर्ती एल्गोरिदम कभी भी 2n + 2 के परिभाषित सीमा को पार नहीं करता है, इसलिए उत्तर मान्य है। मुझे संदेह है कि यह बड़े रजिस्टरों / अधिक बिट्स के लिए इष्टतम समाधान से बहुत दूर जाना शुरू कर देगा, हालांकि।

BFS बनाने के लिए मैंने जिस कोड का उपयोग किया था वह मैला था, स्मृति गहन, टिप्पणी नहीं की, और काफी जानबूझकर शामिल नहीं किया गया था। इसलिए ... आपको मेरे परिणामों पर भरोसा करने की ज़रूरत नहीं है, लेकिन मैं उनमें बहुत आश्वस्त हूं।


एक गैर-बीएफएस समाधान, बढ़िया!
अनातोलीग

मुझे लगता है कि आप सबसे अधिक पैथोलॉजिकल मामलों के लिए भी 4 के एक कारक के भीतर रहेंगे, शायद बेहतर (चूंकि मुझे केवल इष्टतम समाधान के लिए कम बाध्यता का पता है)। जो अभी भी बहुत अच्छा है।
तर्कसंगत

7

पायथन 3, 202 बाइट्स

def S(n):
 q=[(1,0,"")];k=65536
 while q:
  x,y,z=q.pop(0)
  if n in{x,y}:print(z);return
  q+=[((x+y)%k,y,z+"x+=y\n"),(x,(x+y)%k,z+"y+=x\n")]+[(2*x%k,y,z+"x+=x\n")]*(~x&1)+[(x,2*y%k,z+"y+=y\n")]*(~y&1)

(कुछ बाइट्स के लिए @rationalis को धन्यवाद)

यहाँ एक अत्यंत बुनियादी समाधान है। काश मैं आखिरी पंक्ति को बेहतर तरीके से गोल्फ कर सकता, लेकिन मैं वर्तमान में विचारों से बाहर हूं। के साथ बुलाओ S(25)

कार्यक्रम बस एक साधारण बीएफएस करता है जिसमें कोई कैशिंग नहीं है, इसलिए बहुत धीमा है। यहाँ S(97)कुछ नमूना आउटपुट के लिए है:

y+=x
x+=y
x+=x
x+=x
x+=x
x+=x
y+=x
y+=x
x+=y

5

डायलॉग एपीएल, 49 चार्ट्स / बाइट्स *

{0=N←⍵|⍨2*16:⍬⋄0=4|N:⎕←'y+=y'⊣∇N÷2⋄⎕←'y+=x'⊣∇N-1}

एल्गोरिथम बेशर्मी से @CChak के उत्तर से प्रेरित है ।

उदाहरण:

    {0=N←⍵|⍨2*16:⍬⋄0=4|N:⎕←'y+=y'⊣∇N÷2⋄⎕←'y+=x'⊣∇N-1} 25
y+=x
y+=x
y+=y
y+=x
y+=x
y+=y
y+=y
y+=x

Ungolfed:

{
    N←(2*16)|⍵                 # assign the argument modulo 65536 to N
    0=N: ⍬                     # if N = 0, return an empty value (that's a Zilde, not a 0)
    0=4|N: ⎕←'y+=y' ⊣ ∇N÷2     # if N mod 4 = 0, recurse with N÷2 and *then* print 'y+=y'
    ⎕←'y+=x' ⊣ ∇N-1            # otherwise, recurse with N-1 and *then* print 'y+=x'
}

* डायलाग एपीएल एक विरासत चारसेट का समर्थन करता है जिसमें ऊपरी 128 बाइट मूल्यों के लिए एपीएल प्रतीकों का मैप होता है। इसलिए एक एपीएल प्रोग्राम जो केवल ASCII वर्णों का उपयोग करता है और एपीएल प्रतीकों को बाइट्स == चार्ट माना जाता है।


3

पायथन, 183

def S(n):
 b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
 if n<2:return
 while~n&1:n>>=1;a+=1
 while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
 while a:s+=[c,c*b+e*2][i];i=0;a-=1
 print(s)

मैं यह गारंटी नहीं दे सकता कि 2x के भीतर सबसे अधिक संख्या के लिए इष्टतम कार्यक्रम है, लेकिन यह कुशल है। सभी मान्य इनपुट्स के लिए 0 <= n < 65536, यह अनिवार्य रूप से तात्कालिक है, और अधिकतम 33 निर्देशों का एक कार्यक्रम बनाता है। एक मनमाने ढंग से रजिस्टर आकार के लिए n(उस स्थिर को ठीक करने के बाद), O(n)अधिकांश 2n+1निर्देशों के साथ समय लगेगा ।

कुछ बाइनरी लॉजिक

किसी भी विषम संख्या nको 31 चरणों के भीतर पहुँचा जा सकता है: करना y+=x, प्राप्त करना x,y = 1,1, और उसके बाद दोहरीकरण xकरना x+=x(पहले दोहरीकरण के लिए x+=y, जब xसे शुरू करने के लिए विषम है)। xइस तरह से 2 की हर शक्ति तक पहुंच जाएगा (यह सिर्फ एक बाईं-शिफ्ट है), और इसलिए आप y2 की इसी शक्ति को जोड़कर 1 होने का कोई भी बिट सेट कर सकते हैं। चूंकि हम 16-बिट रजिस्टर का उपयोग कर रहे हैं, और प्रत्येक बिट को छोड़कर पहले पहुंचने में एक दोहरीकरण लगता है और एक y+=xसेट करने के लिए, हमें अधिकतम 31 ऑप मिलते हैं।

कोई भी संख्या nकेवल 2 की कुछ शक्ति है, इसे कॉल करें a, एक विषम संख्या के समय, इसे कॉल करें m; यानी n = 2^a * m, या समतुल्य n = m << a। प्राप्त करने के लिए उपरोक्त प्रक्रिया का उपयोग करें m, फिर xइसे तब तक बाएँ-किनारे से रीसेट करें जब तक कि यह 0. x+=yसेट करने के लिए न करें x = m, और फिर xपहले का उपयोग करते हुए, x+=yबाद में डबल करना जारी रखें x+=x

जो aकुछ भी है, वह पाने 16-aके xलिए बदलाव करता है और रीसेट करने के लिए y=mएक अतिरिक्त aशिफ्ट x=0। के बाद एक और aबदलाव xहोगा x=m। तो कुल 16+aशिफ्ट का उपयोग किया जाता है। ऐसे 16-aबिट्स हैं जिन्हें प्राप्त करने के लिए सेट करने की आवश्यकता है m, और उनमें से प्रत्येक को एक लेना होगा y+=x। अंत में हमें एक अतिरिक्त कदम की जरूरत है, जब x=0इसे मी पर सेट किया जाए x+=y। इसलिए किसी भी सम संख्या को प्राप्त करने के लिए यह अधिकतम 33 चरणों में होता है।

तुम्हें पता है, निश्चित रूप से, यह किसी भी आकार रजिस्टर, जिस स्थिति में यह हमेशा अधिक से अधिक लेता है सामान्यीकरण कर सकते हैं 2n-1और 2n+1अजीब और यहां तक कि के लिए ऑप्स n-बिट पूर्णांकों, क्रमशः।

optimality

यह एल्गोरिथ्म एक प्रोग्राम का निर्माण करता है जो विषम संख्याओं के लिए लगभग इष्टतम (यानी 2n+2यदि nचरणों की न्यूनतम संख्या है)। किसी दिए गए विषम संख्या के लिए n, अगर mवें सा है अग्रणी 1, तो किसी भी कार्यक्रम में कम से कम लेता mचरणों को पाने के लिए x=nया y=n, आपरेशन जो रजिस्टरों 'मूल्यों सबसे तेजी से बढ़ जाती है के बाद से x+=xया y+=y(यानी दोहरीकरण) है और यह लेता mकरने के लिए दोहरीकरण The mth bit 1. चूंकि यह एल्गोरिथ्म अधिकांश 2mचरणों में (अधिकतम दो प्रति दोहरीकरण, एक शिफ्ट और एक के लिए y+=x) लेता है , किसी भी विषम संख्या का निकट-आशावादी रूप से प्रतिनिधित्व किया जाता है।

यहां तक ​​कि संख्याएं भी इतनी अच्छी नहीं हैं, क्योंकि यह हमेशा xकुछ भी करने से पहले 16 ऑप्स का उपयोग करता है, और 8, उदाहरण के लिए, 5 चरणों में पहुंचा जा सकता है।

दिलचस्प है, उपरोक्त एल्गोरिथ्म कभी भी उपयोग नहीं करता है y+=y, क्योंकि yहमेशा विषम रखा जाता है। किस स्थिति में, यह वास्तव में केवल 3 परिचालनों के प्रतिबंधित सेट के लिए सबसे छोटा कार्यक्रम हो सकता है।

परिक्षण

# Do an exhaustive breadth-first search to find the shortest program for
# each valid input
def bfs():
    d = {(0,1):0}
    k = 0xFFFF
    s = set(range(k+1))
    current = [(0,1)]
    nexts = []
    def add(pt, dist, n):
        if pt in d: return
        d[pt] = dist
        s.difference_update(pt)
        n.append(pt)
    i = 0
    while len(s) > 0:
        i += 1
        for p in current:
            x,y = p
            add((x,x+y&k), i, nexts)
            add((y,x+y&k), i, nexts)
            if y%2 == 0: add(tuple(sorted((x,y+y&k))), i, nexts)
            if x%2 == 0: add(tuple(sorted((x+x&k,y))), i, nexts)
        current = nexts
        nexts = []
        print(len(d),len(s))

# Mine (@rationalis)
def S(n):
    b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
    if n<2:return ''
    while~n&1:n>>=1;a+=1
    while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
    while a:s+=[c,c*b+e*2][i];i=0;a-=1
    return s

# @CChak's approach
def U(i):
    if i<1:return ''
    return U(i//2)+'y+=y\n' if i%4==0 else U(i-1)+'y+=x\n'

# Use mine on odd numbers and @CChak's on even numbers
def V(i):
    return S(i) if i % 2 == 1 else U(i)

# Simulate a program in the hypothetical machine language
def T(s):
    x,y = 1,0
    for l in s.split():
        if l == 'x+=x':
            if x % 2 == 1: return 1,0
            x += x
        elif l == 'y+=y':
            if y % 2 == 1: return 1,0
            y += y
        elif l == 'x+=y': x += y
        elif l == 'y+=x': y += x
        x %= 1<<16
        y %= 1<<16
    return x,y

# Test a solution on all values 0 to 65535 inclusive
# Max op limit only for my own solution
def test(f):
    max_ops = 33 if f==S else 1000
    for i in range(1<<16):
        s = f(i); t = T(s)
        if i not in t or len(s)//5 > max_ops:
            print(s,i,t)
            break

# Compare two solutions
def test2(f,g):
    lf = [len(f(i)) for i in range(2,1<<16)]
    lg = [len(g(i)) for i in range(2,1<<16)]
    l = [lf[i]/lg[i] for i in range(len(lf))]
    print(sum(l)/len(l))
    print(sum(lf)/sum(lg))

# Test by default if script is executed
def main():
    test()

if __name__ == '__main__':
    main()

मैंने यह जांचने के लिए एक सरल परीक्षण लिखा था कि मेरा समाधान वास्तव में सही परिणाम पैदा करता है, और सभी वैध इनपुट ( 0 <= n < 65536) के लिए कभी भी 33 चरणों में नहीं जाता है ।

इसके अलावा, मैंने इष्टतम आउटपुट के खिलाफ अपने समाधान के आउटपुट की तुलना करने के लिए एक अनुभवजन्य विश्लेषण करने का प्रयास किया - हालांकि, यह पता चला है कि चौड़ाई-पहली खोज हर वैध इनपुट के लिए न्यूनतम आउटपुट लंबाई प्राप्त करने के लिए बहुत अक्षम है n। उदाहरण के लिए, आउटपुट को खोजने के लिए BFS का उपयोग n = 65535उचित समय में समाप्त नहीं होता है। फिर भी मैं bfs()सुझाव के लिए अंदर और बाहर खुला हूँ।

हालाँकि, मैंने @ चीक के खिलाफ अपने स्वयं के समाधान का परीक्षण किया (जैसा कि यहां पायथन में लागू किया गया है U)। मुझे उम्मीद थी कि मेरा और भी बुरा होगा, क्योंकि यह छोटी संख्याओं के लिए बहुत ही अयोग्य है, लेकिन पूरी तरह से दो तरीकों से औसतन, मेरा उत्पादन औसत 10.8% लंबाई से 12.3% कम है। मैंने सोचा कि शायद यह विषम संख्याओं पर अपने स्वयं के समाधान से बेहतर दक्षता के कारण था, इसलिए Vविषम संख्याओं और @ CChak पर भी संख्याओं पर मेरा उपयोग करता है, लेकिन Vबीच में है (लगभग 10% से कम U, 3% से अधिक S)।


1
201 बाइट्स में काफी तर्क है!
अनातोलीग

@analtolyg मैं क्या कह सकता हूं, मुझे गणित और बिट फिडलिंग पसंद है। मैं अन्य दृष्टिकोणों की जांच कर सकता हूं, क्योंकि सम संख्या समाधान में सुधार की गुंजाइश है।
तर्कसंगत

वाह, मुझे x,y='xy'अब तक एहसास नहीं हुआ था। दुर्भाग्य से, मैं स्वरूपण के c*b+e*2साथ संक्षिप्त रूप से फिर से लिखने का एक तरीका नहीं सोच सकता %
rationalis

आह मुझे एहसास नहीं था कि आप इसे कहीं और इस्तेमाल करते हैं। क्या यह सिर्फ मेरा है या S(2)वास्तव में लंबा है?
Sp3000

दुर्भाग्य से, मेरे समाधान के साथ, हर सम संख्या में कम से कम 19 कदम होते हैं (19 S(2)में सबसे छोटा होता है)। मैं का ट्रैक रखने नहीं xऔर yस्पष्ट रूप से है, तो भले ही xपहुँच 2 दूसरे चरण के बाद, यह फिर भी पर जारी है पुनर्स्थापित करने के लिए x0. मैं महसूस करने के लिए जैसे कि वहाँ होना चाहिए एक बेहतर समाधान है, लेकिन के रूप में अभी तक मैं सोच भी नहीं सकते एक।
तर्कसंगत
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.