पाइथन 2 (तेजी से दौड़ें तो पीपे का उपयोग करके चलाएं)
माना जाता है कि लगभग हमेशा 10 राउंड या उससे कम में सही युग्मन का अनुमान लगाया जाता है
मेरा एल्गोरिथ्म मास्टरमाइंड के लिए मेरे उत्तर से मेरे शौक के रूप में लिया गया है ( Ideone में देखें )। यह विचार अनुमान लगाने के लिए है जो सबसे खराब स्थिति में छोड़ी गई संभावनाओं की संख्या को कम करता है। नीचे दिए गए मेरे एल्गोरिथ्म में इसे बल दिया गया है, लेकिन समय बचाने के लिए, यह सिर्फ यादृच्छिक अनुमान लगाता है कि यदि छोड़ी गई संभावनाओं की संख्या इससे अधिक है RANDOM_THRESHOLD
। चीजों को गति देने या बेहतर प्रदर्शन देखने के लिए आप इस पैरामीटर के साथ खेल सकते हैं।
Pypy का उपयोग करके चलाने पर एक रन के लिए औसतन 10s पर एल्गोरिथ्म काफी धीमा है (यदि सामान्य CPython दुभाषिया का उपयोग यह 30 के आसपास है) तो मैं इसे पूरे क्रमपरिवर्तन पर परीक्षण नहीं कर सकता। लेकिन प्रदर्शन काफी अच्छा है, लगभग 30 परीक्षणों के बाद मैंने ऐसा कोई उदाहरण नहीं देखा है जहां यह 10 राउंड या उससे कम में सही युग्मन नहीं पा सके।
वैसे भी, अगर यह वास्तविक जीवन शो में उपयोग किया जाता है, तो इसके पास अगले दौर (एक सप्ताह?) से पहले काफ़ी समय होता है, इसलिए इस एल्गोरिथ्म का वास्तविक जीवन में उपयोग किया जा सकता है = डी
इसलिए मुझे लगता है कि यह मान लेना सुरक्षित है कि औसतन यह 10 अनुमानों या निम्नतर में सही युग्मों को खोजेगा।
इसे स्वयं आज़माएं। मैं अगले कुछ दिनों में गति में सुधार कर सकता हूं (EDIT: आगे सुधार करना मुश्किल लग रहा है, इसलिए मैं सिर्फ कोड छोड़ दूंगा। मैंने केवल यादृच्छिक पिक करने की कोशिश की है, लेकिन यहां तक कि size=7
यह 5040 मामलों में से 3 में विफल रहता है। , इसलिए मैंने चतुर विधि रखने का फैसला किया)। आप इसे निम्नानुसार चला सकते हैं:
pypy are_you_the_one.py 10
या, यदि आप केवल यह देखना चाहते हैं कि यह कैसे काम करता है, तो छोटी संख्या को इनपुट करें (ताकि यह तेजी से चले)
पूर्ण परीक्षण चलाने के लिए (चेतावनी: इसके लिए बहुत लंबा समय लगेगा size
> 7 के ), एक नकारात्मक संख्या डालते हैं।
के लिए पूर्ण परीक्षा size=7
(2 मी 32 में पूरा):
...
(६, ५, ४, १, ३, २, ०): ५ अनुमान
(६, ५, ४, २, ०, १, ३): ५ अनुमान
(६, ५, ४, २, ०, ३, १): ४ अनुमान
(६, ५, ४, २, १, ०, ३): ५ अनुमान
(६, ५, ४, २, १, ३, ०): ६ अनुमान
(६, ५, ४, २, ३, ०, १): ६ अनुमान
(६, ५, ४, २, ३, १, ०): ६ अनुमान
(६, ५, ४, ३, ०, १, २): ६ अनुमान
(६, ५, ४, ३, ०, २, १): ३ अनुमान
(६, ५, ४, ३, १, ०, २): 4 अनुमान
(६, ५, ४, ३, १, २, ०): 4 अनुमान
(६, ५, ४, ३, २, ०, १): ४ अनुमान
(६, ५, ४, ३, २, १, ०): 4 अनुमान
औसत गणना: 5.05
अधिकतम गिनती: 7
न्यूनतम गणना: 1
अंक सफलता: 5040
यदि RANDOM_THRESHOLD
और CLEVER_THRESHOLD
दोनों एक बहुत उच्च मूल्य (जैसे 50000) पर सेट हैं, तो यह एल्गोरिथ्म को सबसे खराब अनुमान लगाने के लिए मजबूर करेगा जो सबसे खराब स्थिति में संभावनाओं की संख्या को कम करता है। यह बहुत धीमा है, लेकिन बहुत शक्तिशाली है। उदाहरण के लिए, यह size=6
दावा करते हुए कि यह अधिकतम 5 राउंड में सही युग्मन पा सकता है।
यद्यपि सन्निकटन (जो औसतन 4.11 राउंड औसत है) का उपयोग करने की तुलना में औसत अधिक है, लेकिन यह हमेशा सफल होता है, यहां तक कि एक राउंड को भी छोड़ दिया जाता है। यह हमारी परिकल्पना को और मजबूत करता है कि कब size=10
, इसे लगभग हमेशा 10 राउंड या उससे कम में सही युग्मों का पता लगाना चाहिए।
परिणाम (3 मी 9 एस में पूरा):
(५, ४, २, १, ०, ३): ५ अनुमान
(५, ४, २, १, ३, ०): ५ अनुमान
(५, ४, २, ३, ०, १): ४ अनुमान
(५, ४, २, ३, १, ०): ४ अनुमान
(५, ४, ३, ०, १, २): ५ अनुमान
(५, ४, ३, ०, २, १): ५ अनुमान
(५, ४, ३, १, ०, २): ५ अनुमान
(५, ४, ३, १, २, ०): ५ अनुमान
(५, ४, ३, २, ०, १): ५ अनुमान
(५, ४, ३, २, १, ०): ५ अनुमान
औसत गणना: 4.41
अधिकतम गणना: 5
न्यूनतम गणना: 1
अंक सफलता: 720
कोड।
from itertools import permutations, combinations
import random, sys
from collections import Counter
INTERACTIVE = False
ORIG_PERMS = []
RANDOM_THRESHOLD = 100
CLEVER_THRESHOLD = 0
class Unbuffered():
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
self.stream.getattr(attr)
sys.stdout = Unbuffered(sys.stdout)
def init(size):
global ORIG_PERMS
ORIG_PERMS = list(permutations(range(size)))
def evaluate(solution, guess):
if len(guess) == len(solution):
cor = 0
for sol, gss in zip(solution, guess):
if sol == gss:
cor += 1
return cor
else:
return 1 if solution[guess[0]] == guess[1] else 0
def remove_perms(perms, evaluation, guess):
return [perm for perm in perms if evaluate(perm, guess)==evaluation]
def guess_one(possible_perms, guessed_all, count):
if count == 1:
return (0,0)
pairs = Counter()
for perm in possible_perms:
for pair in enumerate(perm):
pairs[pair] += 1
perm_cnt = len(possible_perms)
return sorted(pairs.items(), key=lambda x: (abs(perm_cnt-x[1]) if x[1]<perm_cnt else perm_cnt,x[0]) )[0][0]
def guess_all(possible_perms, guessed_all, count):
size = len(possible_perms[0])
if count == 1:
fact = 1
for i in range(2, size):
fact *= i
if len(possible_perms) == fact:
return tuple(range(size))
else:
return tuple([1,0]+range(2,size))
if len(possible_perms) == 1:
return possible_perms[0]
if count < size and len(possible_perms) > RANDOM_THRESHOLD:
return possible_perms[random.randint(0, len(possible_perms)-1)]
elif count == size or len(possible_perms) > CLEVER_THRESHOLD:
(_, next_guess) = min((max(((len(remove_perms(possible_perms, evaluation, next_guess)), next_guess) for evaluation in range(len(next_guess))), key=lambda x: x[0])
for next_guess in possible_perms if next_guess not in guessed_all), key=lambda x: x[0])
return next_guess
else:
(_, next_guess) = min((max(((len(remove_perms(possible_perms, evaluation, next_guess)), next_guess) for evaluation in range(len(next_guess))), key=lambda x: x[0])
for next_guess in ORIG_PERMS if next_guess not in guessed_all), key=lambda x: x[0])
return next_guess
def main(size=4):
if size < 0:
size = -size
init(size)
counts = []
for solution in ORIG_PERMS:
count = run_one(solution, False)
counts.append(count)
print '%s: %d guesses' % (solution, count)
sum_count = float(sum(counts))
print 'Average count: %.2f' % (sum_count/len(counts))
print 'Max count : %d' % max(counts)
print 'Min count : %d' % min(counts)
print 'Num success : %d' % sum(1 for count in counts if count <= size)
else:
init(size)
solution = ORIG_PERMS[random.randint(0,len(ORIG_PERMS)-1)]
run_one(solution, True)
def run_one(solution, should_print):
if should_print:
print solution
size = len(solution)
cur_guess = None
possible_perms = list(ORIG_PERMS)
count = 0
guessed_one = []
guessed_all = []
while True:
count += 1
# Round A, guess one pair
if should_print:
print 'Round %dA' % count
if should_print:
print 'Num of possibilities: %d' % len(possible_perms)
cur_guess = guess_one(possible_perms, guessed_all, count)
if should_print:
print 'Guess: %s' % str(cur_guess)
if INTERACTIVE:
evaluation = int(raw_input('Number of correct pairs: '))
else:
evaluation = evaluate(solution, cur_guess)
if should_print:
print 'Evaluation: %s' % str(evaluation)
possible_perms = remove_perms(possible_perms, evaluation, cur_guess)
# Round B, guess all pairs
if should_print:
print 'Round %dB' % count
print 'Num of possibilities: %d' % len(possible_perms)
cur_guess = guess_all(possible_perms, guessed_all, count)
if should_print:
print 'Guess: %s' % str(cur_guess)
guessed_all.append(cur_guess)
if INTERACTIVE:
evaluation = int(raw_input('Number of correct pairs: '))
else:
evaluation = evaluate(solution, cur_guess)
if should_print: print 'Evaluation: %s' % str(evaluation)
if evaluation == size:
if should_print:
print 'Found %s in %d guesses' % (str(cur_guess), count)
else:
return count
break
possible_perms = remove_perms(possible_perms, evaluation, cur_guess)
if __name__=='__main__':
size = 4
if len(sys.argv) >= 2:
size = int(sys.argv[1])
if len(sys.argv) >= 3:
INTERACTIVE = bool(int(sys.argv[2]))
main(size)