我發佈了這個問題over at CodeReview,但我意識到這不是一個Haskell問題,因爲它是一個算法問題。有沒有辦法避免不必要的遞歸?
Haskell代碼可以找到on my github repo但我認爲代碼並不像一般概念那麼重要。
基本上,該程序計算出Kalaha(瑞典變體)遊戲中最優的第一套動作。只考慮第一個「轉向」,所以我們假設你開始並且沒有計算從對手移動的點開始的任何事情。
Kalaha board http://www.graf-web.at/mwm/kalaha.jpg
板開始與空存儲和在每個盆中彈子的等量。
你開始輪到你,選擇一個非空的鍋在你身邊,從鍋中挑出所有的大理石,然後在盤子上放一塊大理石,在板上移動。如果您的最後一顆大理石在商店中落地,您可以再轉一圈。如果你在一個非空的非專用鍋中着陸,你可以拿起該鍋的所有內容並繼續。最後,如果你落在一個空鍋裏,轉身就傳給對手。
到目前爲止,我已經通過選擇所有可能的路徑,然後根據最終商店中的彈珠數量對它們進行排序來解決此問題。一條道路可能意味着從你的一個鍋子開始,做所有必要的拾取和移動,看看你是在商店還是在空罐子裏。如果你在商店登陸,你會繼續,現在有很多新的分支,因爲你身邊有非空的罐子。
問題在於,如果你從花盆中的五個彈珠開始,它已經有很多路徑。跳到六,ghci用完內存。
我無法弄清楚如何降低成本的原因是因爲我認爲每個路徑在計算過程中都是必需的。儘管我只需要生成數千(或數百萬)中最多三條路徑(最好的路徑),但剩下的路徑需要運行以查看它們是否比以前的路徑更好。
如果一個更長(通常更好),那麼這是好的,但成本高。如果它比任何以前的路徑都短,那麼程序仍然必須計算該路徑才能找到該路徑。
有沒有辦法解決這個問題,還是計算定義所需的所有路徑?
爲了計算最好的單一動作而不嘗試通過對手的動作向前看,可以在這裏採用動態編程:每次計算從特定遊戲狀態的最佳移動時,將移動和結果狀態存儲在一張桌子。可能有許多國家(最多可以將30個分爲6個分箱),但我相信商店裏的彈珠數量可以忽略不計。 – 2012-07-12 15:26:46
我沒有證據,但我認爲應該有可能在一回閤中贏得比賽。文中沒有提到的一個規則是,如果你用完了可彈奏的彈珠,你將所有的彈珠都記錄在對手的坑中,所以目標是一回合用完一個完美的彈珠。如果以空坑結束的移動被忽略,問題將至少減少到指數複雜性而不是NP難度。 – dflemstr 2012-07-12 15:47:28
我會注意到,「計算所有路徑」並不一定意味着「內存不足」,如果你可以垃圾收集你已經考慮過的路徑。 – 2012-07-12 16:25:43