आप एक हैं? (मास्टरमाइंड व्युत्पन्न)


15

मैं तुम्हारे लिए एक कठिन मिल गया है!

मेरी प्रेमिका हाल ही में एमटीवी (यूएसए) के एक नए शो में आई थी। यह एक भयानक शो है, और इस पर हर कोई कचरा है, लेकिन "गेम" बहुत दिलचस्प है। विकिपीडिया से:

आप एक हैं? उन 20 लोगों का अनुसरण करता है जो अपना सही मैच खोजने के लिए हवाई में एक साथ रह रहे हैं। यदि 10 पुरुष और 10 महिलाएं दस सप्ताह में सभी दस सही मैचों को सही ढंग से चुनने में सक्षम हैं, तो वे उनके बीच विभाजित करने के लिए $ 1 मिलियन का लाभ उठाएंगे।

अब खेल के हिस्से के लिए (विकिपीडिया से भी):

प्रत्येक एपिसोड में कलाकारों को जोड़ा जाएगा, जो मानते हैं कि उनका सही मैच एक चुनौती में प्रतिस्पर्धा करना है। चुनौती के विजेता डेट पर जाएंगे, और सच बूथ में अपने मैच का परीक्षण करने का मौका होगा। कास्ट मेंबर्स जीतने वाले कपल्स में से एक का चयन करेंगे कि वह सही बूथ पर जाए या नहीं यह निर्धारित करने के लिए कि वे एक परफेक्ट मैच हैं या नहीं। यह मैचों की पुष्टि करने का एकमात्र तरीका है। प्रत्येक एपिसोड एक मेल खाने वाले समारोह के साथ समाप्त होता है जहां जोड़े को बताया जाएगा कि उनके पास कितने सही मैच हैं, लेकिन कौन से मैच सही नहीं हैं।

टी एल; डॉ: यह एक मास्टरमाइंड व्युत्पन्न है (एम (10,10) विशिष्ट होने के लिए)। खेल के नियम इस प्रकार हैं:

  1. आप 10 के 2 सेट से शुरू करते हैं, आइए उन्हें सेट करें A: {A, B, C, D, E, F, G, H, I, J} और सेट 2: {1,2,3,4,5, 6,7,8,9,10}

  2. कंप्यूटर {A1, B2, C3, D4, E5, F6, G7, H8, I9, J10} के रूप में एक समाधान (आपको दिखाई नहीं देता है) बनाता है, जहां सेट A में सदस्यों को 1-से -1 मैप किया जाता है सेट करना 2. किसी समाधान का दूसरा उदाहरण {A2, B5, C10, D8, E1, F7, G6, H4, I9, J3} हो सकता है।

  3. अपनी पहली बारी से पहले, आप पूछ सकते हैं कि क्या आपकी पसंद का एक विशेष जोड़ा सही है। आपका प्रश्न {A1} (जैसे {C8}) के रूप में होगा, और आपको या तो 1 (मतलब सही) या 0 प्राप्त होगा (मतलब आपका अनुमान गलत है)।

  4. आपका पहला वास्तविक मोड़। आप अपना पहला अनुमान {A1, B2, C3, D4, E5, F6, G7, H8, I9, J10}, या अपनी पसंद के किसी भी क्रमपरिवर्तन के रूप में लगाते हैं। आपके अनुमान में किसी भी आइटम के गुणकों को शामिल नहीं किया जा सकता है अर्थात {A1, A2, A3, A4, A5, B6, B7, B8, B9, B10} का अनुमान मान्य नहीं है। प्रत्येक मोड़ के बाद, कंप्यूटर आपको सही मिलानों की संख्या बताता है , लेकिन जो मैच सही नहीं हैं।

  5. चरण 3 और 4 को तब तक दोहराएं जब तक कि आप हर मैच को सही न करें (यानी 10 की प्रतिक्रिया), या जब तक आपकी 10 चालें पूरी न हो जाएं (जो भी जल्द हो)। यदि आप इसे अपने 10 वें मोड़ पर या उससे पहले हल करते हैं, तो आप $ 1 मिलियन जीतते हैं। अन्यथा, आप हार जाते हैं, और कुछ लोग (या पत्र और संख्या) अपनी 10 बिल्लियों के साथ अनंत काल बिताने के लिए अकेले घर जाते हैं।

यह एक सबसे छोटी कोड प्रतियोगिता नहीं है। जो व्यक्ति अनुमानों के कम से कम औसत संख्या में यादृच्छिक मिलान को हल कर सकता है, वह विजेता होगा। चतुर खेल खेलने और गणना की गति में भी कारक की संभावना होगी। मैं मान रहा हूं कि औसत की संख्या लगभग निश्चित रूप से 10 से अधिक होगी, इसलिए आप की जीत $ 1 मिलियन का पुरस्कार (संभवतः एमटीवी द्वारा भुगतान किया गया, मुझे नहीं) पतला है। सिर्फ कलाकारों के लिए भव्य पुरस्कार जीतना कितना असंभव है?

नोट: इसे {A1, B2, ...} प्रारूप में डालना आवश्यक नहीं है। मैंने बस उस फॉर्म का उपयोग इस प्रश्न में किया कि यह बिल्कुल स्पष्ट हो सके कि पहेली क्या है। यदि आप इसे इस रूप में नहीं रखते हैं, तो कृपया बताएं कि इसे कैसे कॉल करें।

सौभाग्य!


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

जहाँ तक मैं बता सकता हूँ कि सवाल का मास्टरमाइंड के साथ खेलने में कोई लेना-देना नहीं है। यह एक गेम के लिए पूछता है जो उपयोगकर्ता को इसे खेलने की अनुमति देता है।
feersum

1
फिर पॉप-कॉन्टेस्ट इसके लिए टैग नहीं है।

1
@ hosch250 विजेता के लिए अद्यतन मानदंड
dberm22

2
7 उत्थान, 2 पसंदीदा, और कोई जवाब नहीं। मुझे पता था कि यह एक कठिन था!
dberm22

जवाबों:


6

पाइथन 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)

यह वास्तव में अविश्वसनीय है। मैं इसे 100 बार चला चुका हूं, और इसका समाधान खोजने में अभी 10 से अधिक अनुमान लगाने हैं। मैंने एक जोड़ी 10 देखी है, और एक जोड़ी 6 भी। (आप कहते हैं कि आपने ऐसा कोई उदाहरण नहीं देखा है जहाँ यह 10 राउंड के अंतर्गत सही युग्मन नहीं पा सकता है। यह शायद "10 या उससे कम राउंड में" कहना चाहिए, लेकिन यह सिर्फ शब्दार्थ है।) यह शानदार है। मुझे लगता है कि आपका लैम्ब्डा मूल्य एंट्रॉपी की माप का कुछ प्रकार है जो आपको इष्टतम अनुमान लगाने की अनुमति देता है, लेकिन मैं यह नहीं देखता कि यह कैसे या कहां सेट है। यह सिर्फ मुझे घना किया जा रहा है, आपके कार्यक्रम का अभियोग नहीं। अतुल्य काम!
dberm22 15

यह सबसे खराब स्थिति ( len(remove_perms ...)भाग) में छोड़ी गई संभावनाओं की संख्या को कम करने की कोशिश कर रहा है । और हाँ, मेरा मतलब <= 10 चक्कर =) में था। वास्तव में इष्टतम अनुमान से ऊपर कोड में Btw कभी नहीं बनाया गया है, क्योंकि मैंने रखा है CLEVER_THRESHOLD=0, जिसका मतलब है कि यह केवल संभावनाओं की सूची से अनुमान लगाने की कोशिश करेगा, हालांकि इष्टतम अनुमान इस सेट के बाहर हो सकता है। लेकिन मैंने समय बचाने के लिए इसे निष्क्रिय करने का फैसला किया। मैंने इसके लिए पूर्ण परीक्षण जोड़ा size=7, यह दर्शाता है कि यह हमेशा सफल होता है।
जस्ट

1
मैं 'क्लेवर थ्रेशोल्ड = 0' (9,8,7,6,5,4,3,3,1,0 से शुरू) और सभी क्रमपरिवर्तन के माध्यम से पीछे की ओर काम करते हुए आपके कोड को रात भर चला रहा हूं। मैं अब तक केवल 2050 हूं, लेकिन 13 मामले ऐसे हैं, जहां इसने 11 मोड़ लिए हैं। नमूना प्रिंट आउट - (९, 9, 9, ४, ०, ६, ३, २, १, ५): ९ अनुमान, औसत गणना: Average.२ ९, अधिकतम गणना: ११, न्यूनतम गणना: ४, अंक सफलता: २०३,, अंक मूल्यांकन किया गया: 2050. यदि 'चतुर थ्रेशोल्ड' ठीक से सेट किया गया था, तो मुझे विश्वास है कि उन 11 में से 10 बन जाएंगे। फिर भी, औसतन 8.3 शानदार है।
dberm22

@ dberm22: हाँ, इस धीमे एल्गोरिदम को रात भर चलाने के लिए धन्यवाद! मैंने पूर्ण परीक्षण चलाया size=8और पाया कि यदि इस सेटिंग का उपयोग किया जाता है तो नवीनतम संस्करण में केवल 40308 सफलताएं (40320 के बजाय) हैं। लेकिन यह अभी भी 99.97% सफलता दर है! लगता है कि हम टीवी शो के आयोजक दिवालिया हो सकते हैं।
जस्टफ्लोर

3

CJam -19 बदल जाता है- एक बेवकूफ की रणनीति

यह एक गंभीर जवाब नहीं बल्कि एक प्रदर्शन है। यह एक बेवकूफ समाधान है जहां वह बारी के दूसरे भाग से प्रदान की गई सही युग्मन जानकारी की संख्या को ध्यान में नहीं रखता है। पूरी तरह से यादृच्छिक युग्मन के साथ, इसमें औसतन 27 सप्ताह लगते हैं। यह उत्तर अपर्याप्त है, जैसा कि मैंने कहा है, लेकिन इंगित करता है कि एक बुद्धिजीवी समूह के लिए अंतर (बहुत अधिक बौद्धिक है कि यह कार्यक्रम) संभवतः उतना पतला नहीं है जितना आप उम्मीद कर सकते हैं। जितने अधिक बौद्धिक एल्गोरिदम मैंने लिखे हैं, लेकिन उन्हें चलाने में अधिक समय लगता है इसलिए मैं वास्तव में उनसे उत्तर प्राप्त कर सकता हूं।

अद्यतन: नीचे दिए गए कोड को राज्य का उपयोग करने के लिए अपडेट किया गया था कि यह उन लोगों को हटा दें जो काम नहीं करते हैं यदि केवल वही सही हैं जो हम पहले से ही जानते थे कि वे सही थे। यह मेरे यादृच्छिक "सही उत्तर" जनरेटर को दिखाने के लिए भी संपादित किया गया था। औसत परिणाम अब केवल 19 है। यह अभी भी एक गूंगा समाधान है लेकिन यह पिछले मामूली से बेहतर है।

A,{__,mr=_@@-}A*;]sedS*:Z;

ZS/:i:G;                               "Set the input (goal) to G";
{UU@{G2$==@+\)}%~;}:C;                 "This is the tool to count how many of an array agree with G";
{:Y;1$1$<{Y-}%Yaa+@@)>{Y-}%+}:S;       "for stack A X Y, sets the Xth value in the array to Y";
{:Y;1$1$<2$2$=Y-a+@@)>+}:R;            "for stack A X Y, removes Y from the Xth value in the array";

1:D;                                   "Set turn counter to one. if zero exits loop";

A,]A*                                  "array of arrays that has all possible values for an ordering";

{                                      "start of loop";

_V=(\;_GV=={V\SV):V;}{V\R}?            "Guesses a number for the first unknown. If right sets the pair; else erases it";

_[{(_,_{mr=}{;;11}?:Y\{Y-}%}A*;]_C     "guesses random possible arrangement and determines how many are right, error=11";
\_{+}*45-:Y{Y;{_11={;BY-}{}?}%}{}?\    "error correct by including the missing number";

_V={;V:X>{X\RX):X;}%~LV}{}?            "if all new are wrong, makes sure they aren't guessed again";
_A={Dp0:D;;p;}{D):D;;;}?               "If all are right, prints it an tells loop to exit.  Else increments counter";

D}g                                    "repeat from start of loop";

यह भी ध्यान दें: मैला त्रुटि से निपटने क्योंकि यह प्रोग्राम करने के लिए आसान है कि तब एक और अधिक बुद्धिमान विधि है।
kaine

एक समाधान को लागू करने के लिए वास्तव में पर्याप्त बहादुर होने के लिए +1। मैं वास्तव में काफी हैरान हूं कि सही समाधान का अनुमान लगाने में औसतन केवल 27 मोड़ लगते हैं। मुझे लगता है कि जैसा कि आप सही ढंग से अनुमान लगाते हैं, बाद के मैच तेजी से (अच्छी तरह से, तथ्यात्मक रूप से) खोजने में आसान होते हैं। धन्यवाद! मुझे यह देखने में दिलचस्पी होगी कि क्या कोई 10 से कम प्राप्त कर सकता है। आपने मुझे आशा दी है!
dberm22

अगर 27 आश्चर्य की बात है कि देखो! सभी मजाक उड़ाते हुए मुझे लगता है कि एक उपाय जो 10 या कम से कम ग्वारेंट का औसतन संभव है। मैं उचित समय सीमा में काम करने के लिए इस तरह के एल्गोरिथ्म को प्राप्त नहीं कर सकता।
किन्नर

19 ... मैं और भी हैरान हूं। बस एक सवाल हालांकि ... आपके कार्यक्रम में, जहां आप कहते हैं "पहले अज्ञात के लिए एक संख्या का अनुमान लगाते हैं। अगर सही जोड़ी बनाता है, तो इसे मिटा देता है"। यदि यह गलत है ... तो आपको इसे उन मैचों की सूची में जोड़ना चाहिए जिन्हें आप जानते हैं कि वे सही नहीं हैं, इसलिए आप इसे फिर से अनुमान नहीं लगाते हैं (या तो क्रमपरिवर्तन में, या अलग अनुमान के रूप में)।
dberm22

इसका मतलब है इसे संभावनाओं की सूची से मिटा दें; मेरे पास संभावित लोगों की सूची है जो असंभव लोगों की सूची नहीं है। ओह, और मैं यह उल्लेख करना भूल गया कि यह पुरुष सरणी में स्थिति है और महिला संख्या 0-9 (या इसके विपरीत) है। अगर यह अधिक गंभीर सबमिशन होता तो मैं A5 B2 आदि फॉर्मेट का इस्तेमाल करता।
kaine

3

फास्ट मल्टी थ्रेडेड C ++ संस्करण

मुझे पता है कि यह थ्रेड सक्रिय होने के बाद कुछ समय हो गया है, लेकिन मेरे पास साझा करने के लिए एक ठंडा अतिरिक्त है: यहां C ++ के न्यूनतम एल्गोरिदम का कार्यान्वयन है आप के ? , जो प्रत्येक संभावित अनुमान के मूल्यांकन को गति देने के लिए मल्टी-थ्रेडिंग का उपयोग करता है।

यह संस्करण पायथन संस्करण की तुलना में बहुत तेज है (100x से अधिक तेजी से जब मूल पायथन संस्करण अधिकतम पर सेट हो जाता है RANDOM_THRESHOLD और CLEVER_THRESHOLD) पर । यह किसी भी यादृच्छिक अनुमान का उपयोग नहीं करता है, बल्कि सभी क्रमपरिवर्तन का मूल्यांकन करता है और इसके अनुमान को प्रस्तुत करता है क्योंकि यह अनुमान है कि संभव समाधानों की सबसे बड़ी संख्या (सबसे खराब स्थिति की प्रतिक्रिया) को समाप्त करता है।

छोटे गेम के लिए, "ayto -n" कॉलिंग सभी n पर गेम चलाएगी! संभव छिपे हुए मिलान, और अंत में आपको परिणामों का एक संक्षिप्त सारांश देगा।

चूंकि यह अभी भी सभी 10 का मूल्यांकन करने के लिए असाध्य है! संभव छिपे हुए मिलान, यदि आप "ayto 10" कहते हैं, उदाहरण के लिए, सिम्युलेटर अपने पहले तीन अनुमान लगाता है, तो अपने अनुमान का चयन करने के लिए मिनिमैक्स चलाता है और मानता है कि इसे सबसे खराब स्थिति का मूल्यांकन दिया गया था। यह हमें एक छिपे हुए वेक्टर के लिए "सबसे खराब स्थिति वाला मार्ग" की ओर ले जाता है जो संभवतः वैक्टर की श्रेणी में है जो एल्गोरिदम को पहचानने के लिए अधिकतम संख्या में अनुमान लगाता है। इस अनुमान का परीक्षण नहीं किया गया है।

अप करने के लिए एन = 9 , वहाँ एक सिमुलेशन कि अधिक से अधिक ले लिया है नहीं किया गया है n हल करने के लिए बदल जाता है।

इसका परीक्षण करने के लिए, एक उदाहरण संकलन निम्नलिखित होगा:

g++ -std=c++11 -lpthread -o ayto ayto.cpp

यहाँ आउटपुट के साथ एक छोटा सा उदाहरण दिया गया है:

$ ./ayto -4
Found (0, 1, 2, 3) in 2 guesses.
Found (0, 1, 3, 2) in 3 guesses.
Found (0, 2, 1, 3) in 2 guesses.
Found (0, 2, 3, 1) in 3 guesses.
Found (0, 3, 1, 2) in 2 guesses.
Found (0, 3, 2, 1) in 2 guesses.
Found (1, 0, 2, 3) in 1 guesses.
Found (1, 0, 3, 2) in 3 guesses.
Found (1, 2, 0, 3) in 3 guesses.
Found (1, 2, 3, 0) in 3 guesses.
Found (1, 3, 0, 2) in 3 guesses.
Found (1, 3, 2, 0) in 3 guesses.
Found (2, 0, 1, 3) in 3 guesses.
Found (2, 0, 3, 1) in 3 guesses.
Found (2, 1, 0, 3) in 3 guesses.
Found (2, 1, 3, 0) in 3 guesses.
Found (2, 3, 0, 1) in 3 guesses.
Found (2, 3, 1, 0) in 3 guesses.
Found (3, 0, 1, 2) in 3 guesses.
Found (3, 0, 2, 1) in 3 guesses.
Found (3, 1, 0, 2) in 3 guesses.
Found (3, 1, 2, 0) in 3 guesses.
Found (3, 2, 0, 1) in 3 guesses.
Found (3, 2, 1, 0) in 3 guesses.
***** SUMMARY *****
Avg. Turns: 2.75
Worst Hidden Vector: (0, 1, 3, 2) in 3 turns.

कोड

/* Multithreaded Mini-max Solver for MTV's Are You The One? */

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <algorithm>
#include <numeric>
#include <string>
#include <vector>
#include <map>
#include <thread>
#include <cmath>

#define TEN_FACT (3628800)
#define NUM_CHUNKS (8)

using std::cout;
using std::cin;
using std::endl;
using std::vector;
using std::string;
using std::map;
using std::pair;
using std::find;
using std::abs;
using std::atoi;
using std::next_permutation;
using std::max_element;
using std::accumulate;
using std::reverse;
using std::thread;

struct args {
    vector<string> *perms;
    vector<string> *chunk;
    pair<string, int> *cd;
    int thread_id;
};

void simulate_game(const string &hidden, map<string, int> &turns_taken,
                   bool running_all);
bool picmp(const pair<string, int> &p1, const pair<string, int> &p2);
double map_avg(const map<string, int> &mp);
int nrand(int n);
int evaluate(const string &sol, const string &query);
vector<string> remove_perms(vector<string> &perms, int eval, string &query);
pair<string, int> guess_tb(vector<string> &perms, vector<string> &guessed_tb, int turn);
pair<string, int> guess_pm(vector<string> &perms, vector<string> &guessed, int turn);
void make_chunks(vector<string> &orig, vector<vector<string> > &chunks, int n);
string min_candidate(pair<string, int> *candidates, int n);
void get_score(struct args *args);
int wc_response(string &guess, vector<string> &perms);
bool prcmp(pair<int, int> x, pair<int, int> y);
void sequence_print(string s);
struct args **create_args(vector<string> &perms, pair<string, int> *cd, vector<string> &chunk, int thread_id);


vector<string> ORIGPERMS;

int main(int argc, char **argv)
{
    int sz;
    map<string, int> turns_taken;
    const string digits = "0123456789";
    bool running_all = false;

    if (argc != 2) {
        cout << "usage: 'ayto npairs'" << endl;
        return 1;
    } else {
        if ((sz = atoi(argv[1])) < 0) {
            sz = -sz;
            running_all = true;
        }
        if (sz < 3 || sz > 10) {
            cout << "usage: 'ayto npairs' where 3 <= npairs <= 10" << endl;;
            return 1;
        }
    }

    // initialize ORIGPERMS and possible_perms
    string range = digits.substr(0, sz);
    do {
        ORIGPERMS.push_back(range);
    } while (next_permutation(range.begin(), range.end()));

    if (running_all) {
        for (vector<string>::const_iterator it = ORIGPERMS.begin();
             it != ORIGPERMS.end(); ++it) {
            simulate_game(*it, turns_taken, running_all);
        }
        cout << "***** SUMMARY *****\n";
        cout << "Avg. Turns: " << map_avg(turns_taken) << endl;
        pair<string, int> wc = *max_element(turns_taken.begin(),
                                            turns_taken.end(), picmp);
        cout << "Worst Hidden Vector: ";
        sequence_print(wc.first);
        cout << " in " << wc.second << " turns." << endl;
    } else {
        string hidden = ORIGPERMS[nrand(ORIGPERMS.size())];
        simulate_game(hidden, turns_taken, running_all);
    }

    return 0;
}

// simulate_game:  run a single round of AYTO on hidden vector
void simulate_game(const string &hidden, map<string, int> &turns_taken,
                   bool running_all)
{
    vector<string> possible_perms = ORIGPERMS;
    pair<string, int> tbguess;
    pair<string, int> pmguess;
    vector<string> guessed;
    vector<string> guessed_tb;
    int e;
    int sz = hidden.size();

    if (!running_all) {
        cout << "Running AYTO Simulator on Hidden Vector: ";
        sequence_print(hidden);
        cout << endl;
    }

    for (int turn = 1; ; ++turn) {
        // stage one: truth booth
        if (!running_all) {
            cout << "**** Round " << turn << "A ****" << endl;
            cout << "Num. Possibilities: " << possible_perms.size() << endl;
        }
        tbguess = guess_tb(possible_perms, guessed_tb, turn);
        if (!running_all) {
            cout << "Guess: ";
            sequence_print(tbguess.first);
            cout << endl;
            e = tbguess.second;
            cout << "Worst-Case Evaluation: " << e << endl;
        } else {
            e = evaluate(hidden, tbguess.first);
        }
        possible_perms = remove_perms(possible_perms, e, tbguess.first);

        // stage two: perfect matching
        if (!running_all) {
            cout << "Round " << turn << "B" << endl;
            cout << "Num. Possibilities: " << possible_perms.size() << endl;
        }
        pmguess = guess_pm(possible_perms, guessed, turn);

        if (!running_all) {
            cout << "Guess: ";
            sequence_print(pmguess.first);
            cout << endl;
            e = pmguess.second;
            cout << "Worst-Case Evaluation: " << e << endl;
        } else {
            e = evaluate(hidden, pmguess.first);
        }
        if (e == sz) {
            cout << "Found ";
            sequence_print(pmguess.first);
            cout << " in " << turn << " guesses." << endl;
            turns_taken[pmguess.first] = turn;
            break;
        }

        possible_perms = remove_perms(possible_perms, e, pmguess.first);
    }
}

// map_avg:  returns average int component of a map<string, int> type
double map_avg(const map<string, int> &mp)
{
    double sum = 0.0;

    for (map<string, int>::const_iterator it = mp.begin(); 
         it != mp.end(); ++it) {
        sum += it->second;
    }

    return sum / mp.size();
}

// picmp:  comparison function for pair<string, int> types, via int component
bool picmp(const pair<string, int> &p1, const pair<string, int> &p2)
{
    return p1.second < p2.second;
}

// nrand:  random integer in range [0, n)
int nrand(int n)
{
    srand(time(NULL));

    return rand() % n;
}

// evaluate:  number of black hits from permutation or truth booth query
int evaluate(const string &sol, const string &query)
{
    int hits = 0;

    if (sol.size() == query.size()) {
        // permutation query
        int s = sol.size();
        for (int i = 0; i < s; i++) {
            if (sol[i] == query[i])
                ++hits;
        }
    } else {
        // truth booth query
        if (sol[atoi(query.substr(0, 1).c_str())] == query[1])
            ++hits;
    }

    return hits;
}

// remove_perms:  remove solutions that are no longer possible after an eval
vector<string> remove_perms(vector<string> &perms, int eval, string &query)
{
    vector<string> new_perms;

    for (vector<string>::iterator i = perms.begin(); i != perms.end(); i++) {
        if (evaluate(*i, query) == eval) {
            new_perms.push_back(*i);
        }
    }

    return new_perms;
}

// guess_tb:  guesses best pair (pos, val) to go to the truth booth
pair<string, int> guess_tb(vector<string> &possible_perms,
                           vector<string> &guessed_tb, int turn)
{
    static const string digits = "0123456789";
    int n = possible_perms[0].size();
    pair<string, int> next_guess;

    if (turn == 1) {
        next_guess.first = "00";
        next_guess.second = 0;
    } else if (possible_perms.size() == 1) {
        next_guess.first = "0" + possible_perms[0].substr(0, 1);
        next_guess.second = 1;
    } else {
        map<string, double> pair_to_count;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                pair_to_count[digits.substr(i, 1) + digits.substr(j, 1)] = 0;
            }
        }

        // count up the occurrences of each pair in the possible perms
        for (vector<string>::iterator p = possible_perms.begin();
             p != possible_perms.end(); p++) {
            int len = possible_perms[0].size();
            for (int i = 0; i < len; i++) {
                pair_to_count[digits.substr(i, 1) + (*p).substr(i, 1)] += 1;
            }
        }

        double best_dist = 1;
        int perm_cnt = possible_perms.size();
        for (map<string, double>::iterator i = pair_to_count.begin();
             i != pair_to_count.end(); i++) {
            if (find(guessed_tb.begin(), guessed_tb.end(), i->first)
                == guessed_tb.end()) {
                // hasn't been guessed yet
                if (abs(i->second/perm_cnt - .5) < best_dist) {
                    next_guess.first = i->first;
                    best_dist = abs(i->second/perm_cnt - .5);
                    if (i->second / perm_cnt < 0.5) // occurs in < half perms
                        next_guess.second = 0;
                    else                            // occurs in >= half perms
                        next_guess.second = 1;
                }
            }
        }
    }

    guessed_tb.push_back(next_guess.first);

    return next_guess;
}

// guess_pm:  guess a full permutation using minimax
pair<string, int> guess_pm(vector<string> &possible_perms,
                           vector<string> &guessed, int turn)
{
    static const string digits = "0123456789";
    pair<string, int> next_guess;
    vector<vector<string> > chunks;
    int sz = possible_perms[0].size();

    // on first turn, we guess "0, 1, ..., n-1" if truth booth was correct
    // or "1, 0, ..., n-1" if truth booth was incorrect
    if (turn == 1) {
        int fact, i;
        for (i = 2, fact = 1; i <= sz; fact *= i++)
            ;
        if (possible_perms.size() == fact) {
            next_guess.first = digits.substr(0, sz);
            next_guess.second = 1;
        } else {
            next_guess.first = "10" + digits.substr(2, sz - 2);
            next_guess.second = 1;
        }
    } else if (possible_perms.size() == 1) {
        next_guess.first = possible_perms[0];
        next_guess.second = possible_perms[0].size();
    } else {
        // run multi-threaded minimax to get next guess
        pair<string, int> candidates[NUM_CHUNKS];
        vector<thread> jobs;
        make_chunks(ORIGPERMS, chunks, NUM_CHUNKS);
        struct args **args = create_args(possible_perms, candidates, chunks[0], 0);

        for (int j = 0; j < NUM_CHUNKS; j++) {
            args[j]->chunk = &(chunks[j]);
            args[j]->thread_id = j;
            jobs.push_back(thread(get_score, args[j]));
        }
        for (int j = 0; j < NUM_CHUNKS; j++) {
            jobs[j].join();
        }

        next_guess.first = min_candidate(candidates, NUM_CHUNKS);
        next_guess.second = wc_response(next_guess.first, possible_perms);

        for (int j = 0; j < NUM_CHUNKS; j++)
            free(args[j]);
        free(args);
    }

    guessed.push_back(next_guess.first);

    return next_guess;
}

struct args **create_args(vector<string> &perms, pair<string, int> *cd, vector<string> &chunk, int thread_id)
{
    struct args **args = (struct args **) malloc(sizeof(struct args*)*NUM_CHUNKS);
    assert(args);
    for (int i = 0; i < NUM_CHUNKS; i++) {
        args[i] = (struct args *) malloc(sizeof(struct args));
        assert(args[i]);
        args[i]->perms = &perms;
        args[i]->cd = cd;
    }

    return args;
}

// make_chunks:  return pointers to n (nearly) equally sized vectors
//                from the original vector
void make_chunks(vector<string> &orig, vector<vector<string> > &chunks, int n)
{
    int sz = orig.size();
    int chunk_sz = sz / n;
    int n_with_extra = sz % n;
    vector<string>::iterator b = orig.begin();
    vector<string>::iterator e;

    for (int i = 0; i < n; i++) {
        int m = chunk_sz;    // size of this chunk
        if (n_with_extra) {
            ++m;
            --n_with_extra;
        }
        e = b + m;
        vector<string> subvec(b, e);
        chunks.push_back(subvec);
        b = e;
    }
}

// min_candidate:  string with min int from array of pair<string, ints>
string min_candidate(pair<string, int> *candidates, int n)
{
    int i, minsofar;
    string minstring;

    minstring = candidates[0].first;
    minsofar = candidates[0].second;
    for (i = 1; i < n; ++i) {
        if (candidates[i].second < minsofar) {
            minsofar = candidates[i].second;
            minstring = candidates[i].first;
        }
    }

    return minstring;
}

// get_score:  find the maximum number of remaining solutions over all
//             possible responses to the query s
//             this version takes a chunk and finds the guess with lowest score
//             from that chunk
void get_score(struct args *args)
{
    // parse the args struct
    vector<string> &chunk = *(args->chunk);
    vector<string> &perms = *(args->perms);
    pair<string, int> *cd = args->cd;
    int thread_id = args->thread_id;

    typedef vector<string>::const_iterator vec_iter;
    int sz = perms[0].size();

    pair<string, int> best_guess;
    best_guess.second = perms.size();
    int wc_num_remaining;
    for (vec_iter s = chunk.begin(); s != chunk.end(); ++s) {
        vector<int> matches(sz + 1, 0);
        for (vec_iter p = perms.begin(); p != perms.end(); ++p) {
            ++matches[evaluate(*s, *p)];
        }
        wc_num_remaining = *max_element(matches.begin(), matches.end());
        if (wc_num_remaining < best_guess.second) {
            best_guess.first = *s;
            best_guess.second = wc_num_remaining;
        }
    }

    cd[thread_id] = best_guess;

    return;
}

// wc_response:  the response to guess that eliminates the least solutions
int wc_response(string &guess, vector<string> &perms)
{
    map<int, int> matches_eval;

    for (vector<string>::iterator it = perms.begin(); it!=perms.end(); ++it) {
        ++matches_eval[evaluate(guess, *it)];
    }

    return max_element(matches_eval.begin(), matches_eval.end(), prcmp)->first;
}

// prcmp:  comparison function for pair<int, int> types in map
bool prcmp(pair<int, int> x, pair<int, int> y)
{
    return x.second < y.second;
}

void sequence_print(const string s)
{
    for (string::const_iterator i = s.begin(); i != s.end(); i++) {
        if (i == s.begin())
            cout << "(";
        cout << *i;
        if (i != s.end() - 1)
            cout << ", ";
        else
            cout << ")";
    }
}

मैं यह करने के लिए चले गए हैं आप एक? अद्यतन, तेज कोड के साथ GitHub पर
क्रिस च्यूट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.