簡體   English   中英

Memoization Recursion C ++

[英]Memoization Recursion C++

我正在實現一個帶有memoization的遞歸函數來加速。 該計划的重點如下:

我洗了一副紙牌(有相同數量的紅色和黑色卡片)並開始面朝上處理它們。 在任何一張卡片之后,你可以說“停止”,此時我每發出一張紅卡就會支付1美元,而你支付的每張黑卡就要支付1美元。 什么是你的最佳策略,你玩這個游戲需要多少錢?

我的遞歸函數如下:

double Game::Value_of_game(double number_of_red_cards, double number_of_black_cards)
{
    double value, key;


    if(number_of_red_cards == 0)
    {
    Card_values.insert(Card_values.begin(), pair<double, double> (Key_hash_table(number_of_red_cards, number_of_black_cards), number_of_black_cards));
    return number_of_black_cards;
    }
    else if(number_of_black_cards == 0)
    {
    Card_values.insert(Card_values.begin(), pair<double, double> (Key_hash_table(number_of_red_cards, number_of_black_cards), 0));
    return 0;
    }

    card_iter = Card_values.find(Key_hash_table(number_of_red_cards, number_of_black_cards));
    if(card_iter != Card_values.end())
    {
        cout << endl << "Debug: [" << number_of_red_cards << ", " << number_of_black_cards << "] and value = " << card_iter->second << endl;
    return card_iter->second; 
    }

    else 
    {
    number_of_total_cards = number_of_red_cards + number_of_black_cards;
        prob_red_card = number_of_red_cards/number_of_total_cards;
        prob_black_card = number_of_black_cards/number_of_total_cards;

    value = max(((prob_red_card*Value_of_game(number_of_red_cards - 1, number_of_black_cards)) + 
             (prob_black_card*Value_of_game(number_of_red_cards, number_of_black_cards - 1))), 
             (number_of_black_cards - number_of_red_cards));
    cout << "Check: value = " << value << endl;

    Card_values.insert(Card_values.begin(), pair<double, double> (Key_hash_table(number_of_red_cards, number_of_black_cards), value));

        card_iter = Card_values.find(Key_hash_table(number_of_red_cards , number_of_black_cards ));
        if(card_iter != Card_values.end());
        return card_iter->second;
     } 
}

double Game::Key_hash_table(double number_of_red_cards, double number_of_black_cards)
{
    double key = number_of_red_cards + (number_of_black_cards*91);
    return key; 
}

第三個if語句是代碼的“memoization”部分,它存儲了所有必要的值。 保存在地圖中的值可以被認為是一個矩陣,這些值將對應於某些#red卡和#black卡。 真正令人討厭的是,當我總共執行8張卡的代碼(4個黑色和4個紅色)時,我得到了錯誤的答案。 但是當我執行10張卡的代碼時,我的答案是錯誤的,但現在我對4個黑人和4個紅色的答案是正確的(8張牌)! 同樣可以說是12張牌,我得到12張牌的錯誤答案,但10張牌的正確答案,依此類推。 代碼中有一些錯誤,但我無法弄清楚。

實際上沒有人回答這個問題。 所以我會嘗試一下,雖然nneonneo實際上已經把他或她的手指放在問題的可能來源上。

在這種情況下,第一個問題可能實際上不是問題,但是像拇指一樣伸出......你使用double來保存一個你主要視為整數的值。 在這種情況下,在大多數系統上,這可能沒問題。 但作為一般做法,這是非常糟糕的。 特別是因為你檢查一個double是否完全等於0.在大多數系統中,對於大多數編譯器來說,一個double可以保持整數值達到相當大的尺寸,只要你限制自己添加,減去和乘以其他整數或雙打偽裝成整數以獲得新值。

但是,這可能不是您所看到的錯誤的根源,它只是讓每個優秀的程序員都會為臭臭的代碼敲響警鍾。 它應該是固定的。 你真正需要它們成為雙打的唯一一次是你計算紅色或黑色的相對概率。

這讓我想到了可能是你的問題。 您的代碼中有這兩個語句:

number_of_total_cards = number_of_red_cards + number_of_black_cards;
prob_red_card = number_of_red_cards/number_of_total_cards;
prob_black_card = number_of_black_cards/number_of_total_cards;

當然,這應該是:

number_of_total_cards = number_of_red_cards + number_of_black_cards;
prob_red_card = number_of_red_cards/double(number_of_total_cards);
prob_black_card = number_of_black_cards/double(number_of_total_cards);

因為你是一個優秀的程序員並將這些變量聲明為整數。

推測prob_red_cardprob_black_carddouble類型的變量。 但是它們並沒有在您向我們展示的代碼中的任何位置聲明。 這意味着無論它們在何處聲明,或者它們的類型是什么,它們必須由Game::Value_of_game的遞歸調用樹中的所有子調用有效地共享。

幾乎可以肯定不是你想要的。 這使得很難推斷出這些變量的值以及這些值在函數的遞歸調用樹中的任何給定調用期間所代表的值。 它們實際上必須是局部變量才能使算法易於分析。 幸運的是,它們似乎只在特定if語句的else子句中使用。 因此,當它們最初被賦值時,可以聲明它們。 這可能是這段代碼應該讀的內容:

unsigned const int number_of_total_cards = number_of_red_cards + number_of_black_cards;
const double prob_red_card = number_of_red_cards/double(number_of_total_cards);
const double prob_black_card = number_of_black_cards/double(number_of_total_cards);

請注意,我也聲明它們為const 優良作法是聲明在變量的生命周期內不會發生變化的任何變量值為const 它通過要求編譯器在您意外編寫不正確的代碼時告訴您,幫助您編寫更正確的代碼。 它也可以幫助編譯器生成更好的代碼,盡管在這種情況下,即使對代碼進行簡單的分析也會發現它們在生命周期內沒有被修改並且可以被視為const,所以大多數體面的優化器基本上都會為你提供const 。代碼優化的目的,盡管如果你不小心地以非常規的方式使用它們,那么仍然不會讓編譯器告訴你的好處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM