Python 2 (Pypy kullanarak çalıştırılırsa daha hızlı çalıştır)
Neredeyse her zaman 10 veya daha az turda doğru eşleştirmeyi tahmin ettiğine inanılıyor
Algoritmam beyni benim hobim olarak yanıtımdan alınmıştır (bkz. Ideone ). Fikir, en kötü durumda kalan olasılık sayısını en aza indiren tahminin bulunmasıdır. Altındaki algoritmam sadece kaba kuvvet uygular, ancak zaman kazanmak için, kalan olasılıkların sayısından daha büyükse rastgele tahmin seçer RANDOM_THRESHOLD
. İşleri hızlandırmak veya daha iyi performans görmek için bu parametre ile oynayabilirsiniz.
Pypy kullanarak çalıştırırsanız algoritma oldukça yavaş, ortalama 10 saniye (normal CPython yorumlayıcısı kullanıyorsanız 30 saniye civarında) bu yüzden tüm permütasyonlarda test edemiyorum. Ancak performans oldukça iyi, yaklaşık 30 testten sonra 10 veya daha düşük turda doğru eşleştirmeyi bulamadığı bir örnek görmedim.
Her neyse, eğer bu gerçek hayat şovunda kullanılıyorsa, bir sonraki turdan önce (bir hafta?) Çok zaman var, bu yüzden bu algoritma gerçek hayatta kullanılabilir = D
Bu nedenle, bunun ortalama 10 veya daha düşük tahminlerde doğru eşleşmeleri bulacağını varsaymanın güvenli olduğunu düşünüyorum.
Kendin dene. Önümüzdeki birkaç gün içinde hızını artırabilir (EDIT: daha da geliştirmek zor görünüyor, bu yüzden sadece kodu olduğu gibi bırakacağım. Sadece rastgele seçim yapmaya çalıştım, ama hatta size=7
, 5040 vakanın 3'ünde başarısız oluyor , bu yüzden akıllı yöntemi kullanmaya karar verdim). Şu şekilde çalıştırabilirsiniz:
pypy are_you_the_one.py 10
Veya sadece nasıl çalıştığını görmek istiyorsanız, daha küçük bir sayı girin (böylece daha hızlı çalışır)
Tam bir test çalıştırmak için (uyarı: size
> 7 için çok uzun sürer ), negatif bir sayı girin.
İçin tam test size=7
(2m 32s içinde tamamlandı):
...
(6, 5, 4, 1, 3, 2, 0): 5 tahmin
(6, 5, 4, 2, 0, 1, 3): 5 tahmin
(6, 5, 4, 2, 0, 3, 1): 4 tahmin
(6, 5, 4, 2, 1, 0, 3): 5 tahmin
(6, 5, 4, 2, 1, 3, 0): 6 tahmin
(6, 5, 4, 2, 3, 0, 1): 6 tahmin
(6, 5, 4, 2, 3, 1, 0): 6 tahmin
(6, 5, 4, 3, 0, 1, 2): 6 tahmin
(6, 5, 4, 3, 0, 2, 1): 3 tahmin
(6, 5, 4, 3, 1, 0, 2): 7 tahmin
(6, 5, 4, 3, 1, 2, 0): 7 tahmin
(6, 5, 4, 3, 2, 0, 1): 4 tahmin
(6, 5, 4, 3, 2, 1, 0): 7 tahmin
Ortalama sayım: 5.05
Maksimum sayı: 7
Min. Sayı: 1
Başarı sayısı: 5040
Eğer RANDOM_THRESHOLD
ve CLEVER_THRESHOLD
her ikisi de çok yüksek bir değere (50000 gibi) ayarlanmışsa, algoritmayı en kötü durumda olasılık sayısını en aza indiren en uygun tahminin bulunması için zorlar. Bu çok yavaş ama çok güçlü. Örneğin, onu çalıştırmak size=6
en fazla 5 turda doğru eşleştirmeleri bulabileceğini iddia eder.
Ortalama, yaklaşık olarak ortalamaya göre daha yüksek olmasına rağmen (ortalama 4.11 mermidir), ancak her zaman başarılı olur, daha da fazla, bir turdan fazla yedek kaldı. Bu da size=10
, neredeyse her zaman 10 veya daha az turda doğru eşleşmeleri bulması gerektiği hipotezimizi daha da güçlendirir .
Sonuç (3m 9s'de tamamlandı):
(5, 4, 2, 1, 0, 3): 5 tahmin
(5, 4, 2, 1, 3, 0): 5 tahmin
(5, 4, 2, 3, 0, 1): 4 tahmin
(5, 4, 2, 3, 1, 0): 4 tahmin
(5, 4, 3, 0, 1, 2): 5 tahmin
(5, 4, 3, 0, 2, 1): 5 tahmin
(5, 4, 3, 1, 0, 2): 5 tahmin
(5, 4, 3, 1, 2, 0): 5 tahmin
(5, 4, 3, 2, 0, 1): 5 tahmin
(5, 4, 3, 2, 1, 0): 5 tahmin
Ortalama sayı: 4.41
Maksimum sayı: 5
Min. Sayı: 1
Başarı sayısı: 720
Kod.
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)