Collatz शैली में अंडा शिकार


11

द ग्रेट एपीआई ईस्टर एग हंट से प्रेरित !

सारांश

आपका काम "Collatz अंतरिक्ष" में एक पूर्व निर्धारित पूर्णांक के लिए खोज करना है (बाद में समझाया जाना) संभव सबसे कम कदम का उपयोग करना।

परिचय

यह चुनौती प्रसिद्ध Collatz अनुमान पर आधारित है जो उम्मीद करता है कि यहाँ हर कोई कम से कम के बारे में सुना होगा। यहां प्रिंट द सुपर कोलाज़ेट नंबरों से लिया गया रिकैप है

Collatz अनुक्रम (भी 3x + 1 समस्या कहा जाता है) है, जहां आप किसी भी सकारात्मक पूर्णांक के साथ शुरू इस उदाहरण के लिए हम 10 का उपयोग करेगा, और यह करने के लिए कदम के इस सेट लागू होते हैं:

if n is even:
    Divide it by 2
if n is odd:
    Multiply it by 3 and add 1
repeat until n = 1

Collatz दूरी C(m,n)दो संख्याओं के बीच mऔर nइस चुनौती के प्रयोजन के लिए, दो संख्याओं के बीच की दूरी है Collatz ग्राफ (का उपयोग करते हुए: है, जो परिभाषित किया गया है इस प्रकार है (मुझे इस अवधारणा के बारे में बताने के लिए @tsh को क्रेडिट) 21और 13उदाहरण के रूप में ):

m(इस मामले में 21) के लिए Collatz अनुक्रम लिखें :

21, 64, 32, 16, 8, 4, 2, 1

n(इस मामले में 13) के लिए Collatz अनुक्रम लिखें :

13, 40, 20, 10, 5, 16, 8, 4, 2, 1

अब गिनती करें कि केवल एक सीक्वेंस में कितने नंबर दिखाई देते हैं। यह Collatz mऔर के बीच दूरी के रूप में परिभाषित किया गया है n। इस मामले में 8, अर्थात्,

21, 64, 32, 13, 40, 20, 10, 5

इसलिए हम दोनों के बीच Collatz दूरी है 21और 13के रूप में C(21,13)=8

C(m,n) निम्नलिखित अच्छे गुण हैं:

C(m,n)=C(n,m)
C(m,n)=0 iff. m=n

उम्मीद है कि C(m,n)अब की परिभाषा स्पष्ट है। आइए Collatz अंतरिक्ष में अंडे का शिकार करना शुरू करें!

खेल की शुरुआत में, एक नियंत्रक एक ईस्टर अंडे की स्थिति तय करता है, जो इसके एक-आयामी समन्वय द्वारा व्यक्त की जाती है: अंतराल में एक पूर्णांक [p,q](दूसरे शब्दों में, एक पूर्णांक के बीच pऔर q, दोनों समावेशी होते हैं)।

अंडे की स्थिति पूरे खेल में स्थिर रहती है। हम इस समन्वय को निरूपित करेंगे r

अब आप प्रारंभिक अनुमान लगा सकते हैं 0 , और यह नियंत्रक द्वारा दर्ज किया जाएगा। यह आपका 0 वां राउंड है। यदि आप इतने भाग्यशाली हैं कि आपने इसे पहले स्थान (यानी 0 = r) पर प्राप्त किया है, तो खेल समाप्त होता है, और आपका स्कोर 0(स्कोर कम, बेहतर) है। अन्यथा, आप 1 राउंड में प्रवेश करते हैं और आप एक नया अनुमान लगाते हैं 1 , यह तब तक चलता है जब तक कि आप इसे सही नहीं मिला, अर्थात एन = आर, और आपका स्कोर होगा n

0 के बाद के प्रत्येक दौर के लिए, नियंत्रक आपको निम्नलिखित प्रतिक्रियाओं में से एक देता है ताकि आप दी गई जानकारी के आधार पर बेहतर अनुमान लगा सकें। मान लें कि आप वर्तमान में nवें दौर में हैं और इसलिए आपका अनुमान एक n है

  • "आपने ढूंढ लिया!" यदि n = r, तो जिस स्थिति में खेल समाप्त होता है और आप स्कोर करते हैं n
  • "तुम करीब हैं :)" अगर सी (एक एन , आर) <सी (एक n-1 , आर)
  • "तुम अंडा चारों ओर चक्कर काटते रहे हैं" अगर सी (एक एन , आर) = सी (एक n-1 , आर)
  • "तुम दूर कर रहे हैं :(" अगर सी (एक एन , आर)> सी (एक n-1 , आर)

कुछ बाइट्स को बचाने के लिए, मैं ऊपर दिए गए आदेश में प्रतिक्रियाओं को "राइट", "क्लोज़र", "समान", "फ़ेथर" कहूंगा।

यहाँ एक उदाहरण के साथ खेल है p=1,q=15

  • एक 0 = 10
  • एक 1 = 11, प्रतिक्रिया: "क्लोज़र"
  • एक 2 = 13, प्रतिक्रिया: "आगे"
  • एक 3 = 4, प्रतिक्रिया: "आगे"
  • एक 4 = 3, प्रतिक्रिया: "क्लोज़र"
  • एक 5 = 5, प्रतिक्रिया: "वही"
  • एक 6 = 7, प्रतिक्रिया: "ठीक है"

स्कोर: 6

चुनौती

सर्वश्रेष्ठ स्कोर के साथ खेल खेलने के लिए एक नियतात्मक रणनीति डिज़ाइन करें p=51, q=562

उत्तर एल्गोरिदम का विस्तार से वर्णन करना चाहिए। आप एल्गोरिथ्म को स्पष्ट करने में मदद करने वाले किसी भी कोड को संलग्न कर सकते हैं। यह कोडगुल्फ नहीं है इसलिए आपको सुपाठ्य कोड लिखने के लिए प्रोत्साहित किया जाता है।

उत्तरों में सबसे खराब स्कोर शामिल होना चाहिए जो वे सभी संभावित मामलों के लिए प्राप्त कर सकते हैं r, और सबसे खराब स्कोर जीत के साथ। टाई के मामले में, एल्गोरिदम जिसमें सभी संभावित rएस के लिए एक बेहतर औसत स्कोर है (जो कि उत्तर में भी शामिल होना चाहिए) जीत। आगे टाई ब्रेकर नहीं हैं और हमारे पास अंत में कई विजेता हो सकते हैं।

चश्मा

बाउंटी (पहला उत्तर पोस्ट होने के बाद जोड़ा गया)

मैं व्यक्तिगत रूप से एक उत्तर देने की पेशकश कर सकता हूं, जहां सभी अनुमानों को सीमा के भीतर बनाया गया है, [51,562]जबकि अभी भी काफी कम स्कोर है।


क्या आपके पास कोई नियंत्रक है?
user202729

वह नहीं जो मूल प्रश्न में एक जैसा है।
वीजुन झोउ

1
C (m, n) Collatz ग्राफ पर m, n की दूरी है ।
tsh

मैं स्वयं इस अवधारणा के साथ आया था और Collatz ग्राफ को नहीं जानता था। मुझे यह बताने के लिए धन्यवाद। मैं प्रश्न में जानकारी शामिल करूंगा।
वीजुन झोउ

जवाबों:


5

रूबी, 196

यह कठिन था कि मैंने शुरू में सोचा था। मुझे बहुत सारे अस्पष्ट मामलों को संभालना पड़ा और बहुत सारे बदसूरत कोड समाप्त हो गए। लेकिन बहुत मज़ा आया! :)

रणनीति

प्रत्येक Collatz अनुक्रम 2 (पूर्व: [16, 8, 4, 2, 1]) की शक्तियों के अनुक्रम के साथ समाप्त होता है। जैसे ही 2 की शक्ति का सामना होता है, हम 2 तक पहुंचते हैं, जब तक कि हम 1. तक नहीं पहुंच जाते हैं। चलो एक क्रम निकटतम p22 में 2 की पहली शक्ति को कॉल करते हैं (क्योंकि यह Collatz दूरी का उपयोग करके हमारे नंबर के लिए 2 की निकटतम शक्ति भी है)। दी गई सीमा (51-562) के लिए, सभी संभावित निकटतम pow2 संख्याएं हैं: [16, 64, 128, 256, 256, 1024]।

लघु संस्करण

एल्गोरिथ्म प्रदर्शन करता है:

  • एक द्विआधारी खोज वर्तमान संख्या में 2 की निकटतम शक्ति का पता लगाने के लिए
  • लक्ष्य संख्या की खोज होने तक अनुक्रम में हर पिछले तत्व का पता लगाने के लिए एक रेखीय खोज।

विस्तृत संस्करण

लक्ष्य संख्या के साथ एक खेल को देखते हुए r, रणनीति निम्नलिखित है:

  1. 2 की शक्ति का पता लगाने के लिए द्विआधारी खोज का उपयोग करें rजो यथासंभव कुछ चरणों में निकटतम है।
  2. यदि 2 की निकटतम शक्ति जो मिली थी, वह समाधान है। अन्यथा 3 तक जारी रखें।
  3. चूंकि 2 की शक्ति जो पाई गई थी, अनुक्रम में होने वाली 2 की पहली शक्ति है, यदि इस प्रकार है कि मान एक (* 3 + 1) ऑपरेशन करके पहुंचा था। (यदि यह / 2 ऑपरेशन के बाद आता है, तो पिछली संख्या 2 की शक्ति भी होगी)। अनुक्रम में पिछले ऑपरेशन की गणना रिवर्स ऑपरेशन (-1 और फिर / 3) करके करें
  4. यदि वह संख्या लक्ष्य है, तो रुकें। अन्यथा 5 तक जारी रखें।
  5. अनुक्रम से ज्ञात वर्तमान संख्या को देखते हुए, पीछे जाने और अनुक्रम में पिछली संख्या की खोज करने की आवश्यकता है। यह ज्ञात नहीं है कि वर्तमान संख्या एक (/ 2) या (* 3 +1) ऑपरेशन द्वारा आई थी, इसलिए एल्गोरिथम उन दोनों को आज़माता है और देखता है कि कौन सा एक नंबर प्राप्त करता है जो लक्ष्य से करीब (Collatz दूरी के रूप में) है ।
  6. यदि नई खोज की गई संख्या सही है, तो रोकें।
  7. नए खोजे गए नंबर का उपयोग करके, चरण 5 पर वापस जाएं।

परिणाम

51-562 रेंज में सभी नंबरों के लिए एल्गोरिथ्म चलाना एक सामान्य पीसी पर एक सेकंड के आसपास होता है और कुल स्कोर 38665 है।

कोड

इसे ऑनलाइन आज़माएं!

require 'set'

# Utility methods
def collatz(n)
  [].tap do |results|
    crt = n
    while true
      results << crt
      break if crt == 1
      crt = crt.even? ? crt / 2 : crt * 3 + 1
    end
  end
end

def collatz_dist(m, n)
  cm = collatz(m).reverse
  cn = collatz(n).reverse
  common_length = cm.zip(cn).count{ |x, y| x == y }
  cm.size + cn.size - common_length * 2
end



GuessResult = Struct.new :response, :score
# Class that can "play" a game, responding
# :right, :closer, :farther or :same when
# presented with a guess
class Game

  def initialize(target_value)
    @r = target_value
    @score = -1
    @dist = nil
    @won = false
  end
  attr_reader :score

  def guess(n)
    # just a logging decorator over the real method
    result = internal_guess(n)
    p [n, result] if LOGGING
    result
  end

  private

  def internal_guess(n)
    raise 'Game already won!' if @won
    @score += 1
    dist = collatz_dist(n, @r)
    if n == @r
      @won = true
      return GuessResult.new(:right, @score)
    end
    response = nil
    if @dist
      response = [:same, :closer, :farther][@dist <=> dist]
    end
    @dist = dist
    GuessResult.new(response)
  end

end

# Main solver code

def solve(game)
  pow2, won = find_closest_power_of_2(game)
  puts "Closest pow2: #{pow2}" if LOGGING

  return pow2 if won
  # Since this is the first power of 2 in the series, it follows that
  # this element must have been arrived at by doing *3+1...
  prev = (pow2 - 1) / 3
  guess = game.guess(prev)
  return prev if guess.response == :right

  solve_backward(game, prev, 300)
end

def solve_backward(game, n, left)
  return 0 if left == 0
  puts "***      Arrived at  ** #{n} **" if LOGGING
  # try to see whether this point was reached by dividing by 2
  double = n * 2
  guess = game.guess(double)
  return double if guess.response == :right

  if guess.response == :farther && (n - 1) % 3 == 0
    # try to see whether this point was reached by *3+1
    third = (n-1) / 3
    guess = game.guess(third)
    return third if guess.response == :right
    if guess.response == :closer
      return solve_backward(game, third, left-1)
    else
      game.guess(n) # reset to n...
    end
  end
  return solve_backward(game, double, left-1)
end


# Every Collatz Sequence ends with a sequence of powers of 2.
# Let's call the first occurring power of 2 in such a sequence
# POW2
#
# Let's iterate through the whole range and find the POW2_CANDIDATES
#
RANGE = [*51..562]
POWERS = Set.new([*0..15].map{ |n| 2 ** n })

POW2_CANDIDATES =
  RANGE.map{ |n| collatz(n).find{ |x| POWERS.include? x} }.uniq.sort
# Turns out that the candidates are [16, 64, 128, 256, 512, 1024]

def find_closest_power_of_2(game)
  min = old_guess = 0
  max = new_guess = POW2_CANDIDATES.size - 1
  guess = game.guess(POW2_CANDIDATES[old_guess])
  return POW2_CANDIDATES[old_guess], true if guess.response == :right
  guess = game.guess(POW2_CANDIDATES[new_guess])
  return POW2_CANDIDATES[new_guess], true if guess.response == :right
  pow2 = nil

  while pow2.nil?

    avg = (old_guess + new_guess) / 2.0

    case guess.response
    when :same
      # at equal distance from the two ends
      pow2 = POW2_CANDIDATES[avg.floor]
      # still need to test if this is correct
      guess = game.guess(pow2)
      return pow2, guess.response == :right
    when :closer
      if old_guess < new_guess
        min = avg.ceil
      else
        max = avg.floor
      end
    when :farther
      if old_guess < new_guess
        max = avg.floor
      else
        min = avg.ceil
      end
    end

    old_guess = new_guess
    new_guess = (min + max) / 2
    new_guess = new_guess + 1 if new_guess == old_guess
    # so we get next result relative to the closer one
    # game.guess(POW2_CANDIDATES[old_guess]) if guess.response == :farther
    guess = game.guess(POW2_CANDIDATES[new_guess])

    if guess.response == :right
      pow2 = POW2_CANDIDATES[new_guess]
      break
    end

    if min == max
      pow2 = POW2_CANDIDATES[min]
      break
    end

  end

  [pow2, guess.response == :right]

end



LOGGING = false

total_score = 0
51.upto(562) do |n|
  game = Game.new(n)
  result = solve(game)
  raise "Incorrect result for #{n} !!!" unless result == n
  total_score += game.score
end
puts "Total score: #{total_score}"

प्रभावशाली। एक मामूली बात है: मेरा मानना ​​है कि टिप्पणियों में से एक को "सही वर्ग" नहीं कहना चाहिए।
वीजुन झोउ

1
@ WeijunZhou आप सही हैं। फिक्स्ड!
क्रिस्टियन लुपस्कू

आपको संभवतः सभी मामलों के लिए सबसे खराब स्कोर शामिल करना चाहिए, जो 196 है।
वीजुन झोउ

3

सबसे खराब स्कोर: 11, योग अंक: 3986

सभी अनुमान सीमा में हैं [51,562]

मेरा एल्गोरिथ्म:

  1. पहली बार अनुमान 512, और संभावित परिणामों का एक सेट बनाए रखें vals, शुरू में सेट में सभी संख्याएँ शामिल हैं [51,562]
  2. प्रत्येक चरण पर, निम्न कार्य करें:

    1. अगले अनुमान का मान ज्ञात guessरेंज में [51,562]ऐसा है कि, जब में मानों vals(छोड़कर guessही) संभावित परिणामों के लिए इसी 3 सेट में विभाजित है Closer, Sameऔर Farther, उन 3 सेट का अधिकतम आकार न्यूनतम है।
      यदि guessउपरोक्त संतुष्ट करने के कई संभावित मूल्य हैं , तो सबसे छोटा चुनें।
    2. मान लें guess
    3. यदि उत्तर "राइट" है, तो किया गया (प्रोग्राम से बाहर निकलें)।
    4. सेट के सभी मानों को valsऐसे निकालें कि वे संभवतः उस परिणाम को न दे सकें।

C ++ और बैश में लिखा मेरा संदर्भ कार्यान्वयन मेरी मशीन पर लगभग 7.6 सेकंड में चलता है और शीर्षक में वर्णित सबसे खराब स्कोर / योग स्कोर देता है।

मेरी मशीन पर हर संभव पहले अनुमान लगाने में लगभग 1.5 घंटे का समय लगेगा। मैं ऐसा करने पर विचार कर सकता हूं।


(पी / एस: गैर-कोड सबमिशन की अनुमति है। यदि आपको मेरे स्कोर पर भरोसा नहीं है, तो बस इसे स्वयं लागू करें और देखें)
user202729

लेकिन अगर आप वास्तव में इसे कुछ कारणों से इसे फिर से लागू किए बिना काम करते देखना चाहते हैं, तो इसे ऑनलाइन आज़माएं !
user202729

एक मिनट रुकिए मैं अपने कार्यक्रम को निर्णय वृक्ष के उत्पादन और उसे स्कोर करने की अनुमति क्यों नहीं दे सकता: | यह बहुत तेज़ होगा ...
user202729
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.