เอามันหรือทิ้งมัน: เกมโชว์สำหรับคอมพิวเตอร์


28

บริบท:

มหาเศรษฐีสันโดษได้สร้างรายการเกมเพื่อดึงดูดโปรแกรมเมอร์ที่ดีที่สุดและสว่างที่สุดในโลก ในวันจันทร์เวลาเที่ยงคืนเขาเลือกบุคคลหนึ่งคนจากกลุ่มผู้สมัครเป็นผู้แข่งขันในสัปดาห์และมอบเกมให้พวกเขา คุณเป็นผู้โชคดีในสัปดาห์นี้!

เกมของสัปดาห์นี้:

โฮสต์ให้คุณเข้าถึง API เพื่อเข้าถึงซองจดหมายดิจิทัลจำนวน 10,000 ซอง ซองจดหมายเหล่านี้จะถูกเรียงลำดับแบบสุ่มและมีค่าเงินดอลลาร์อยู่ในนั้นระหว่าง $ 1 ถึง $ 10,000 (ไม่มีซองจดหมายสองซองที่มีค่าเงินดอลลาร์เดียวกัน)

คุณมี 3 คำสั่งในการกำจัดของคุณ:

  1. อ่าน (): อ่านตัวเลขดอลลาร์ในซองจดหมายที่ด้านบนของสแต็ก

  2. ใช้ (): เพิ่มตัวเลขดอลลาร์ในซองจดหมายลงในกระเป๋าเงินโชว์เกมของคุณและป๊อปอัพซองจดหมายออกจากสแต็ค

  3. ผ่าน (): เปิดซองจดหมายที่ด้านบนของสแต็ก

กฎระเบียบ:

  1. หากคุณใช้ Pass () บนซองจดหมายเงินภายในจะหายไปตลอดกาล

  2. หากคุณใช้ Take () บนซองจดหมายที่มี $ X จากจุดนั้นไปข้างหน้าคุณจะไม่สามารถใช้ Take () บนซองจดหมายที่มี <$ X ใช้ () บนหนึ่งในซองจดหมายเหล่านี้จะเพิ่ม $ 0 ในกระเป๋าเงินของคุณ

เขียนอัลกอริทึมที่เล่นจบเกมด้วยจำนวนเงินสูงสุด

หากคุณกำลังเขียนวิธีแก้ปัญหาใน Python อย่าลังเลที่จะใช้คอนโทรลเลอร์นี้เพื่อทดสอบอัลกอริธึมความอนุเคราะห์จาก @Maltysen: https://gist.github.com/Maltysen/5a4a33691cd603e9aeca

หากคุณใช้คอนโทรลเลอร์คุณจะไม่สามารถเข้าถึง globals ได้คุณสามารถใช้คำสั่ง API ที่ระบุ 3 รายการเท่านั้นและตัวแปรที่กำหนดขอบเขตแบบโลคัล (@Beta Decay)

หมายเหตุ: "สูงสุด" ในกรณีนี้หมายถึงค่ามัธยฐานในกระเป๋าเงินของคุณหลังจากที่ N> 50 ทำงาน ฉันคาดหวังแม้ว่าฉันจะชอบที่จะได้รับการพิสูจน์ผิดว่าค่ามัธยฐานของอัลกอริทึมที่กำหนดจะมาบรรจบกันเมื่อ N เพิ่มขึ้นเป็นอนันต์ รู้สึกอิสระที่จะพยายามเพิ่มค่าเฉลี่ยสูงสุด แต่ฉันรู้สึกว่าค่าเฉลี่ยมีแนวโน้มที่จะถูกโยนออกโดย N ขนาดเล็กกว่าค่ามัธยฐานคือ

แก้ไข: เปลี่ยนจำนวนซองจดหมายเป็น 10k เพื่อการประมวลผลที่ง่ายขึ้นและทำให้ Take () ชัดเจนยิ่งขึ้น

แก้ไข 2: เงื่อนไขรางวัลถูกลบออกไปเนื่องจากโพสต์นี้ในเมตาดาต้า

คะแนนสูงสุดปัจจุบัน:

PhiNotPi - $ 805,479

Reto Koradi - $ 803,960

เดนนิส - $ 770,272 (แก้ไข)

Alex L. - $ 714,962 (แก้ไข)


ฉันนำไปใช้ในทางที่มันแค่คืนค่าเท็จ เนื่องจากคุณสามารถอ่านได้ไม่มีจุดที่แท้จริงของความล้มเหลวของเกมทั้งหมดในการล้มเหลว ()
OganM

4
ในกรณีที่ใคร ๆ ก็ต้องการใช้มันนี่คือคอนโทรลเลอร์ที่ฉันใช้ในการทดสอบอัลกอริทึมของฉัน: gist.github.com/Maltysen/5a4a33691cd603e9aeca
Maltysen

8
ป.ล. คำถามที่ดีและยินดีต้อนรับสู่ Programming Puzzles และ Code Golf :)
trichoplax

3
@ Maltysen ฉันใส่คอนโทรลเลอร์ของคุณลงใน OP ขอบคุณสำหรับผลงาน!
LivingInformation

1
ฉันไม่พบกฎที่ชัดเจนเกี่ยวกับรางวัลบิตคอยน์ แต่มีการอภิปรายเกี่ยวกับรางวัลในโลกแห่งความเป็นจริงที่ผู้คนสามารถมีส่วนร่วมได้
trichoplax

คำตอบ:


9

CJam, $ 87,143 $ 700,424 $ 720,327 $ 727,580 $ 770,272

{0:T:M;1e4:E,:)mr{RM>{RR(*MM)*-E0.032*220+R*<{ERM--:E;R:MT+:T;}{E(:E;}?}&}fRT}
[easi*]$easi2/=N

โปรแกรมนี้จำลองเกมทั้งหมดหลายครั้งและคำนวณค่ามัธยฐาน

วิธีการวิ่ง

ฉันได้คะแนนการส่งของฉันโดยทำการทดสอบ 100,001 ครั้ง:

$ time java -jar cjam-0.6.5.jar take-it-or-leave-it.cjam 100001
770272

real    5m7.721s
user    5m15.334s
sys     0m0.570s

เข้าใกล้

สำหรับแต่ละซองจดหมายเราดำเนินการดังต่อไปนี้:

  • ประมาณจำนวนเงินที่จะหายไปอย่างหลีกเลี่ยงไม่ได้โดยการใช้ซองจดหมาย

    หากRคือเนื้อหาและMคือจำนวนสูงสุดที่ได้รับมาสามารถประมาณได้ว่าเป็นR (R-1) / 2 - M (M + 1) / 2ซึ่งให้เงินทั้งหมดที่มีเนื้อหาXในซองจดหมายช่วงเวลา(M, R)มี

    หากยังไม่มีซองจดหมายผ่านการประเมินจะสมบูรณ์แบบ

  • คำนวณจำนวนเงินที่จะหายไปอย่างหลีกเลี่ยงไม่ได้โดยการส่งซองจดหมาย

    นี่เป็นเพียงเงินที่ซองมี

  • ตรวจสอบว่าผลหารของทั้งสองน้อยกว่า110 + 0.016E หรือไม่โดยที่Eคือจำนวนซองจดหมายที่เหลืออยู่ (ไม่นับซองจดหมายที่ไม่สามารถนับได้อีกต่อไป)

    ถ้าเป็นเช่นนั้นใช้ มิฉะนั้นผ่าน


5
เพราะการใช้ภาษากอล์ฟช่วยอะไร แต่อย่างใด ; P +1 สำหรับ algo
Maltysen

2
ฉันไม่สามารถทำซ้ำผลลัพธ์ของคุณโดยใช้โคลนหลาม: gist.github.com/orlp/f9b949d60c766430fe9c คุณทำคะแนนประมาณ $ 50,000 นั่นเป็นลำดับความสำคัญ
orlp

1
@LivingInformation Trial และข้อผิดพลาด ตอนนี้ฉันกำลังดูการใช้จำนวนที่แน่นอนแทนที่จะเป็นการประมาณ แต่รหัสผลลัพธ์นั้นช้ามาก
Dennis

2
คำตอบนี้ต้องการ upvotes มากกว่าของฉัน! มันฉลาดกว่าทำคะแนนได้สูงกว่าและเล่นกอล์ฟได้ดีกว่า!
Alex L

1
@LivingInformation นี่คือที่อยู่ของฉัน: 17uLHRfdD5JZ2QjSqPGQ1B12LoX4CgLGuV
Dennis

7

Python $ 680,646 $ 714,962

f = (float(len(stack)) / 10000)
step = 160
if f<0.5: step = 125
if f>0.9: step = 190
if read() < max_taken + step:
    take()
else:
    passe()

ใช้จำนวนเงินที่มากขึ้นและมากขึ้นในขั้นตอนขนาดระหว่าง $ 125 ถึง $ 190 วิ่งด้วย N = 10,000 และได้ค่ามัธยฐานของ $ 714962 ขนาดขั้นตอนเหล่านี้มาจากการลองผิดลองถูกและไม่เหมาะสมที่สุด

รหัสเต็มรวมถึงเวอร์ชั่นที่แก้ไขของตัวควบคุม @ Maltysenซึ่งพิมพ์แผนภูมิแท่งขณะที่มันทำงาน:

import random
N = 10000


def init_game():
    global stack, wallet, max_taken
    stack = list(range(1, 10001))
    random.shuffle(stack)
    wallet = max_taken = 0

def read():
    return stack[0]

def take():
    global wallet, max_taken
    amount = stack.pop(0)
    if amount > max_taken:
        wallet += amount
        max_taken = amount

def passe():
    stack.pop(0)

def test(algo):
    results = []
    for _ in range(N):
        init_game()
        for i in range(10000):
            algo()
        results += [wallet]
        output(wallet)
    import numpy
    print 'max: '
    output(max(results))
    print 'median: '
    output(numpy.median(results))
    print 'min: '
    output(min(results))

def output(n):
    print n
    result = ''
    for _ in range(int(n/20000)):
        result += '-'
    print result+'|'

def alg():
    f = (float(len(stack)) / 10000)
    step = 160
    if f<0.5: step = 125
    if f>0.9: step = 190
    if read() < max_taken + step:
        #if read()>max_taken: print read(), step, f
        take()
    else:
        passe()

test(alg)

ที่อยู่ BitCoin: 1CBzYPCFFBW1FX9sBTmNYUJyMxMcmL4BZ7

ส่ง OP ว้าว! ขอบคุณ @LivingInformation!


1
ตัวควบคุมคือของ Maltysen ไม่ใช่ของฉัน
orlp

2
ได้รับการยืนยัน ฉันเพิ่งตั้งค่าคอนโทรลเลอร์และรับหมายเลขที่คล้ายกันมากสำหรับโซลูชันของคุณ พูดอย่างเคร่งครัดฉันคิดว่าคุณต้องรักษาคุณค่าของmax_takenรหัสของคุณเองเพราะมันไม่ได้เป็นส่วนหนึ่งของ API เกมอย่างเป็นทางการ แต่นั่นเป็นเรื่องเล็กน้อยที่จะทำ
Reto Koradi

1
ใช่ max_taken อยู่ในตัวควบคุมของ @ Maltysen หากมีประโยชน์ฉันสามารถโพสต์โซลูชันทั้งหมด (คอนโทรลเลอร์ + อัลกอริทึม) ในหนึ่งบล็อก
Alex L

มันไม่ใช่เรื่องใหญ่อะไร แต่ผมคิดว่าวิธีการที่สะอาดจะใช้เพียงread(), take()และpass()วิธีการในรหัสโพสต์ตั้งแต่ผู้ที่มี "3 คำสั่งที่จำหน่ายของคุณ" ขึ้นอยู่กับความละเอียดในคำถาม
Reto Koradi

@Reto ฉันยินดีที่จะแก้ไขคำถามให้เป็นคำสั่งที่เหมาะสมที่สุด อ่านรับและส่งมีอักขระทั้งหมด 4 ตัวและรู้สึกเหมาะสม แต่ฉันเปิดให้มีการแนะนำ (ตัวอย่างเช่นฉันได้พิจารณาเปลี่ยน "ส่ง" เป็น "ออก" เนื่องจากฉันตั้งชื่อโพสต์ "รับหรือปล่อย ")
LivingInformation

5

C ++, $ 803,960

for (int iVal = 0; iVal < 10000; ++iVal)
{
    int val = game.read();
    if (val > maxVal &&
        val < 466.7f + 0.9352f * maxVal + 0.0275f * iVal)
    {
        maxVal = val;
        game.take();
    }
    else
    {
        game.pass();
    }
}

ผลลัพธ์ที่รายงานคือค่ามัธยฐานจาก 10,001 เกม


คาดเดาและตรวจสอบฉันใช้มัน? หรือว่าคุณใช้อินพุตฟัซเซอร์แบบบางส่วนกับค่าคงที่?
LivingInformation

ฉันใช้อัลกอริธึมการเพิ่มประสิทธิภาพเพื่อกำหนดค่าคงที่
Reto Koradi

คุณคิดว่าการคำนวณแบบไดนามิกในแต่ละจุดจะมีประสิทธิภาพมากกว่าหรือคุณคิดว่าสิ่งนี้กำลังเข้าใกล้ค่าสูงสุดที่คุณจะได้รับ
LivingInformation

ฉันไม่มีเหตุผลที่จะเชื่อว่ามันเป็นกลยุทธ์ในอุดมคติ ฉันหวังว่ามันจะเป็นค่าสูงสุดสำหรับฟังก์ชันเชิงเส้นพร้อมพารามิเตอร์เหล่านี้ ฉันพยายามอนุญาตให้ใช้คำที่ไม่ใช่เชิงเส้นหลายประเภท แต่จนถึงขณะนี้ยังไม่พบสิ่งใดที่ดีกว่าอย่างมีนัยสำคัญ
Reto Koradi

1
ฉันสามารถยืนยันได้ว่าการจำลองสิ่งนี้ให้คะแนนที่รายงานมากกว่า $ 800,000 เล็กน้อย
orlp

3

C ++, ~ $ 815,000

ขึ้นอยู่กับวิธีแก้ปัญหาของ Reto Koradi แต่เปลี่ยนเป็นอัลกอริทึมที่ซับซ้อนยิ่งขึ้นเมื่อมีซองจดหมายเหลือ 100 ซองที่ถูกต้องสับเปลี่ยนสับเปลี่ยนสุ่มและคำนวณลำดับที่เพิ่มขึ้นมากที่สุด มันจะเปรียบเทียบผลลัพธ์ของการถ่ายและไม่รับซองจดหมายและจะเลือกตัวเลือกที่ดีที่สุดอย่างตะกละตะกลาม

#include <algorithm>
#include <iostream>
#include <vector>
#include <set>


void setmax(std::vector<int>& h, int i, int v) {
    while (i < h.size()) { h[i] = std::max(v, h[i]); i |= i + 1; }
}

int getmax(std::vector<int>& h, int n) {
    int m = 0;
    while (n > 0) { m = std::max(m, h[n-1]); n &= n - 1; }
    return m;
}

int his(const std::vector<int>& l, const std::vector<int>& rank) {
    std::vector<int> h(l.size());
    for (int i = 0; i < l.size(); ++i) {
        int r = rank[i];
        setmax(h, r, l[i] + getmax(h, r));
    }

    return getmax(h, l.size());
}

template<class RNG>
void shuffle(std::vector<int>& l, std::vector<int>& rank, RNG& rng) {
    for (int i = l.size() - 1; i > 0; --i) {
        int j = std::uniform_int_distribution<int>(0, i)(rng);
        std::swap(l[i], l[j]);
        std::swap(rank[i], rank[j]);
    }
}

std::random_device rnd;
std::mt19937_64 rng(rnd());

struct Algo {
    Algo(int N) {
        for (int i = 1; i < N + 1; ++i) left.insert(i);
        ival = maxval = 0;
    }

    static double get_p(int n) { return 1.2 / std::sqrt(8 + n) + 0.71; }

    bool should_take(int val) {
        ival++;
        auto it = left.find(val);
        if (it == left.end()) return false;

        if (left.size() > 100) {
            if (val > maxval && val < 466.7f + 0.9352f * maxval + 0.0275f * (ival - 1)) {
                maxval = val;
                left.erase(left.begin(), std::next(it));
                return true;
            }

            left.erase(it);
            return false;
        }

        take.assign(std::next(it), left.end());
        no_take.assign(left.begin(), it);
        no_take.insert(no_take.end(), std::next(it), left.end());
        take_rank.resize(take.size());
        no_take_rank.resize(no_take.size());
        for (int i = 0; i < take.size(); ++i) take_rank[i] = i;
        for (int i = 0; i < no_take.size(); ++i) no_take_rank[i] = i;

        double take_score, no_take_score;
        take_score = no_take_score = 0;
        for (int i = 0; i < 1000; ++i) {
            shuffle(take, take_rank, rng);
            shuffle(no_take, no_take_rank, rng);
            take_score += val + his(take, take_rank) * get_p(take.size());
            no_take_score += his(no_take, no_take_rank) * get_p(no_take.size());
        }

        if (take_score > no_take_score) {
            left.erase(left.begin(), std::next(it));
            return true;
        }

        left.erase(it);
        return false;
    }

    std::set<int> left;
    int ival, maxval;
    std::vector<int> take, no_take, take_rank, no_take_rank;
};


struct Game {
    Game(int N) : score_(0), max_taken(0) {
        for (int i = 1; i < N + 1; ++i) envelopes.push_back(i);
        std::shuffle(envelopes.begin(), envelopes.end(), rng);
    }

    int read() { return envelopes.back(); }
    bool done() { return envelopes.empty(); }
    int score() { return score_; }
    void pass() { envelopes.pop_back(); }

    void take() {
        if (read() > max_taken) {
            score_ += read();
            max_taken = read();
        }
        envelopes.pop_back();
    }

    int score_;
    int max_taken;
    std::vector<int> envelopes;
};


int main(int argc, char** argv) {
    std::vector<int> results;
    std::vector<int> max_results;
    int N = 10000;
    for (int i = 0; i < 1000; ++i) {
        std::cout << "Simulating game " << (i+1) << ".\n";
        Game game(N);
        Algo algo(N);

        while (!game.done()) {
            if (algo.should_take(game.read())) game.take();
            else game.pass();
        }
        results.push_back(game.score());
    }

    std::sort(results.begin(), results.end());
    std::cout << results[results.size()/2] << "\n";

    return 0;
}

น่าสนใจ ฉันคิดว่ามันควรจะเป็นไปได้ที่จะปรับปรุงโดยดูจากค่าที่เหลือสำหรับซองจดหมายสองสามอันสุดท้าย ฉันคิดว่าคุณเล่นกับจุดตัดที่คุณเปลี่ยนกลยุทธ์หรือไม่ มันช้าเกินไปไหมถ้าคุณเปลี่ยนก่อนหน้านี้? หรือผลลัพธ์นั้นแย่ลงจริงหรือ
Reto Koradi

@RetoKoradi ฉันเล่นกับจุดตัดยอดและการตัดก่อนหน้านี้ทั้งคู่ช้าเกินไปและแย่ลง ไม่มากเกินไปน่าแปลกใจตรงไปตรงมาที่ 100 ซองจดหมายที่เรากำลังอยู่แล้วสุ่มตัวอย่างเพียง 1,000 พีชคณิตออกไปได้ 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000.
orlp

3

Java, $ 806,899

นี่คือจากการทดลอง 2501 รอบ ฉันยังคงพยายามปรับให้เหมาะสม ฉันเขียนสองคลาสคือเสื้อคลุมและเครื่องเล่น เสื้อคลุมจะยกตัวอย่างผู้เล่นด้วยจำนวนซองจดหมาย (สำหรับของจริงเสมอ 10,000) จากนั้นเรียกวิธีการนั้นtakeQด้วยค่าของซองจดหมายด้านบน ผู้เล่นจะกลับมาtrueถ้าพวกเขารับมันfalseถ้าพวกเขาผ่านมันไป

ผู้เล่น

import java.lang.Math;

public class Player {
  public int[] V;

  public Player(int s) {
    V = new int[s];
    for (int i = 0; i < V.length; i++) {
      V[i] = i + 1;
    }
    // System.out.println();
  }

  public boolean takeQ(int x) {

    // System.out.println("look " + x);

    // http://www.programmingsimplified.com/java/source-code/java-program-for-binary-search
    int first = 0;
    int last = V.length - 1;
    int middle = (first + last) / 2;
    int search = x;

    while (first <= last) {
      if (V[middle] < search)
        first = middle + 1;
      else if (V[middle] == search)
        break;
      else
        last = middle - 1;

      middle = (first + last) / 2;
    }

    int i = middle;

    if (first > last) {
      // System.out.println(" PASS");
      return false; // value not found, so the envelope must not be in the list
                    // of acceptable ones
    }

    int[] newVp = new int[V.length - 1];
    for (int j = 0; j < i; j++) {
      newVp[j] = V[j];
    }
    for (int j = i + 1; j < V.length; j++) {
      newVp[j - 1] = V[j];
    }
    double pass = calcVal(newVp);
    int[] newVt = new int[V.length - i - 1];
    for (int j = i + 1; j < V.length; j++) {
      newVt[j - i - 1] = V[j];
    }
    double take = V[i] + calcVal(newVt);
    // System.out.println(" take " + take);
    // System.out.println(" pass " + pass);

    if (take > pass) {
      V = newVt;
      // System.out.println(" TAKE");
      return true;
    } else {
      V = newVp;
      // System.out.println(" PASS");
      return false;
    }
  }

  public double calcVal(int[] list) {
    double total = 0;
    for (int i : list) {
      total += i;
    }
    double ent = 0;
    for (int i : list) {
      if (i > 0) {
        ent -= i / total * Math.log(i / total);
      }
    }
    // System.out.println(" total " + total);
    // System.out.println(" entro " + Math.exp(ent));
    // System.out.println(" count " + list.length);
    return total * (Math.pow(Math.exp(ent), -0.5) * 4.0 / 3);
  }
}

เสื้อคลุม

import java.lang.Math;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;

public class Controller {
  public static void main(String[] args) {
    int size = 10000;
    int rounds = 2501;
    ArrayList<Integer> results = new ArrayList<Integer>();
    int[] envelopes = new int[size];
    for (int i = 0; i < envelopes.length; i++) {
      envelopes[i] = i + 1;
    }
    for (int round = 0; round < rounds; round++) {
      shuffleArray(envelopes);

      Player p = new Player(size);
      int cutoff = 0;
      int winnings = 0;
      for (int i = 0; i < envelopes.length; i++) {
        boolean take = p.takeQ(envelopes[i]);
        if (take && envelopes[i] >= cutoff) {
          winnings += envelopes[i];
          cutoff = envelopes[i];
        }
      }
      results.add(winnings);
    }
    Collections.sort(results);
    System.out.println(
        rounds + " rounds, median is " + results.get(results.size() / 2));
  }

  // stol... I mean borrowed from
  // http://stackoverflow.com/questions/1519736/random-shuffling-of-an-array
  static Random rnd = new Random();

  static void shuffleArray(int[] ar) {
    for (int i = ar.length - 1; i > 0; i--) {
      int index = rnd.nextInt(i + 1);
      // Simple swap
      int a = ar[index];
      ar[index] = ar[i];
      ar[i] = a;
    }
  }
}

คำอธิบายโดยละเอียดเพิ่มเติมกำลังจะมาหลังจากฉันเสร็จสิ้นการปรับให้เหมาะสม

แนวคิดหลักคือสามารถประเมินรางวัลจากการเล่นเกมจากซองจดหมายที่กำหนด หากชุดซองจดหมายปัจจุบันคือ {2,4,5,7,8,9} และซองจดหมายด้านบนคือ 5 แสดงว่ามีความเป็นไปได้สองอย่าง:

  • ใช้ 5 และเล่นเกมกับ {7,8,9}
  • ผ่าน 5 และเล่นเกม {2,4,7,8,9}

หากเราคำนวณรางวัลที่คาดหวังจาก {7,8,9} และเปรียบเทียบกับผลตอบแทนที่คาดหวังจาก {2,4,7,8,9} เราจะสามารถบอกได้ว่าการใช้ 5 มีค่าหรือไม่

ตอนนี้คำถามคือให้ชุดซองจดหมายเช่น {2,4,7,8,9} ค่าที่คาดหวังคืออะไร ฉันพบว่ามูลค่าที่คาดหวังน่าจะเป็นสัดส่วนกับจำนวนเงินทั้งหมดในชุด แต่สัดส่วนแปรผกผันกับสแควร์รูทของจำนวนซองจดหมายที่แบ่งเงินเป็น สิ่งนี้มาจาก "สมบูรณ์แบบ" ในการเล่นเกมเล็ก ๆ หลายเกมซึ่งซองจดหมายทั้งหมดมีค่าเกือบเท่ากัน

ปัญหาต่อไปคือวิธีการระบุ " จำนวนซองจดหมายที่มีประสิทธิภาพ " ในทุกกรณีจำนวนของซองจดหมายเป็นที่รู้จักอย่างแน่นอนโดยการติดตามสิ่งที่คุณเห็นและทำ บางอย่างเช่น {234,235,236} เป็นสามซองแน่นอน {231,232,233,234,235} มี 5 แน่นอน แต่ {1,2,234,235,236} ควรนับเป็น 3 และไม่ใช่ซองจดหมายเพราะ 1 และ 2 เกือบไร้ค่า คุณสามารถรับ 1 หรือ 2 ได้ในภายหลังฉันมีความคิดที่จะใช้นอนส์เอนโทรปีเพื่อกำหนดจำนวนซองจดหมายที่มีประสิทธิภาพ

ฉันตั้งเป้าหมายการคำนวณของฉันกับสถานการณ์ที่ค่าซองจดหมายมีการกระจายอย่างสม่ำเสมอในบางช่วงเวลาซึ่งเป็นสิ่งที่เกิดขึ้นระหว่างเกม ถ้าฉันใช้ {2,4,7,8,9} และถือว่ามันเป็นการกระจายความน่าจะเป็นเอนโทรปีของมันคือ 1.50242 จากนั้นฉันก็exp()จะได้ 4.49254 เป็นจำนวนซองจดหมายที่มีประสิทธิภาพ

รางวัลโดยประมาณจาก {2,4,7,8,9} คือ 30 * 4.4925^-0.5 * 4/3 = 18.87

18.1167จำนวนที่แน่นอนคือ

นี่ไม่ใช่การประมาณการที่แน่นอน แต่จริง ๆ แล้วฉันภูมิใจในความเหมาะสมของข้อมูลเมื่อซองจดหมายมีการกระจายอย่างสม่ำเสมอตลอดช่วงเวลา ฉันไม่แน่ใจว่าตัวคูณที่ถูกต้อง (ตอนนี้ฉันใช้ 4/3) แต่นี่คือตารางข้อมูลที่ไม่รวมตัวคูณ

Set of Envelopes                    Total * (e^entropy)^-0.5      Actual Score

{1,2,3,4,5,6,7,8,9,10}              18.759                        25.473
{2,3,4,5,6,7,8,9,10,11}             21.657                        29.279
{3,4,5,6,7,8,9,10,11,12}            24.648                        33.125
{4,5,6,7,8,9,10,11,12,13}           27.687                        37.002
{5,6,7,8,9,10,11,12,13,14}          30.757                        40.945
{6,7,8,9,10,11,12,13,14,15}         33.846                        44.900
{7,8,9,10,11,12,13,14,15,16}        36.949                        48.871
{8,9,10,11,12,13,14,15,16,17}       40.062                        52.857
{9,10,11,12,13,14,15,16,17,18}      43.183                        56.848
{10,11,12,13,14,15,16,17,18,19}     46.311                        60.857

การถดถอยเชิงเส้นตรงระหว่างและคาดว่าจะเกิดขึ้นจริงให้R ^ 2 ค่าของ 0.999994

ขั้นตอนต่อไปของฉันในการปรับปรุงคำตอบนี้คือการปรับปรุงการประมาณค่าเมื่อจำนวนซองจดหมายเริ่มลดลงซึ่งก็คือเมื่อซองจดหมายไม่กระจายอย่างสม่ำเสมอและเมื่อปัญหาเริ่มได้รับอย่างละเอียด


แก้ไข: ในกรณีนี้ถือว่าคุ้มค่าของการ Bitcoins 1PZ65cXxUEEcGwd7E8i7g6qmvLDGqZ5JWgฉันเพียงแค่มีที่อยู่ที่ ขอบคุณ! (นี่คือที่นี่จากเมื่อผู้เขียนท้าทายได้แจกรางวัล)


ส่ง satoshi 20k ให้คุณมากกว่า 805,479 โดยบังเอิญ สำหรับการอ้างอิงจำนวนที่ควรจะเป็นคะแนนของคุณ สนุกกับความผิดพลาดของฉัน :)
LivingInformation

คุณจะใช้หมายเลขด้วยรอบมากขึ้นหรือไม่ จากสิ่งที่ฉันเห็นมีการเปลี่ยนแปลงค่อนข้างน้อยและ 500 ไม่เพียงพอที่จะได้ค่ามัธยฐานที่เสถียร คะแนนของฉันใกล้เคียงกับคุณมากหากฉันวิ่งแค่ 500 รอบ แต่ทุกอย่างขึ้นอยู่กับว่าตัวเลขสุ่มเกิดขึ้นได้อย่างไร หากฉันใช้เมล็ดพันธุ์ที่ผันแปรและดำเนินการ 500 ครั้งสองสามครั้งฉันอาจได้รับคะแนนสูงกว่า
Reto Koradi

@RetoKoradi ฉันจะทำรอบต่อไปแน่นอน
PhiNotPi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.