自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C++11的Lambda使用一例:華容道求解

開發(fā) 后端
華容道是一個有益的智力游戲,游戲規(guī)則不再贅述。用計算機求解華容道也是一道不錯的編程練習(xí)題,為了尋求最少步數(shù),求解程序一般用廣度優(yōu)先搜索算法。華容道的一種常見開局如圖 1 所示。

華容道是一個有益的智力游戲,游戲規(guī)則不再贅述。用計算機求解華容道也是一道不錯的編程練習(xí)題,為了尋求最少步數(shù),求解程序一般用廣度優(yōu)先搜索算法。華容道的一種常見開局如圖 1 所示。

廣度優(yōu)先搜索算法求解華容道的基本步驟:

  1. 準(zhǔn)備兩個“全局變量”,隊列 Q 和和集合 S,S 代表“已知局面”。初時 Q 和 S 皆為空。
  2. 將初始局面加入隊列 Q 的末尾,并將初始局面設(shè)為已知。
  3. 當(dāng)隊列不為空時,從 Q 的隊首取出當(dāng)前局面 curr。如果隊列為空則結(jié)束搜索,表明無解。
  4. 如果 curr 是最終局面(曹操位于門口,圖 2),則結(jié)束搜索,否則繼續(xù)到第 5 步。
  5. 考慮 curr 中每個可以移動的棋子,試著上下左右移動一步,得到新局面 next,如果新局面未知(next ∉ S),則把它加入隊列 Q,并設(shè)為已知。這一步可能產(chǎn)生多個新局面。
  6. 回到第2步。

其中“局面已知”并不要求每個棋子的位置相同,而是指棋子的投影的形狀相同(代碼中用 mask 表示),例如交換圖 1 中的張飛和趙云并不產(chǎn)生新局面,這一規(guī)定可以大大縮小搜索空間。

以上步驟很容易轉(zhuǎn)換為 C++ 代碼,這篇文章重點關(guān)注的是第 5 步的實現(xiàn)。

http://s2.51cto.com/wyfs01/M00/30/C0/wKioOVJcoKSzNcvLAABFu9uq9CE012.jpg

 

  1. // 第 1 步 
  2. std::unordered_set<Mask> seen; 
  3. std::deque<State> queue; 
  4.   
  5. // 第 2 步 
  6. State initial; 
  7. // 填入 initial,略。 
  8. queue.push_back(initial); 
  9. seen.insert(initial.toMask()); 
  10.   
  11. // 第 3 步 
  12. while (!queue.empty()) 
  13.   const State curr = queue.front(); 
  14.   queue.pop_front(); 
  15.   
  16.   // 第 4 步 
  17.   if (curr.isSolved()) 
  18.     break
  19.   
  20.   // 第 5 步 
  21.   for (const State& next : curr.moves()) 
  22.   { 
  23.     auto result = seen.insert(next.toMask()); 
  24.     if (result.second) 
  25.       queue.push_back(next); 
  26.   } 

在以上原始實現(xiàn)中,curr.move() 將返回一個 std::vector<State> 臨時對象。一種節(jié)省開銷的辦法是準(zhǔn)備一個 std::vector<State> “涂改變量”,讓 curr.move() 反復(fù)修改它,比如改成:

  1. // 第 1 步新增一個 scratch 變量 
  2. std::vector<State> nextMoves; 
  3.   
  4. // 第 3 步 
  5. while (!queue.empty()) 
  6.   // ... 
  7.   // 第 5 步 
  8.   curr.fillMoves(&nextMoves); 
  9.   for (const State& next : nextMoves) 
  10.   { /* 略 */ } 

還有一種徹底不用這個 std::vector<State> 的辦法,把一部分邏輯以 lambda 的形式傳給 curr.move(),代碼的結(jié)構(gòu)基本不變:

  1. // 第 3 步 
  2. while (!queue.empty()) 
  3.   // ... 
  4.   // 第 5 步 
  5.   curr.move([&seen, &queue](const State& next) { 
  6.     auto result = seen.insert(next.toMask()); 
  7.     if (result.second) 
  8.       queue.push_back(next); 
  9.   }); 

這樣一來,主程序的邏輯依然清晰,不必要的開銷也降到了最小。

在我最早的實現(xiàn)中,curr.move() 的參數(shù)是 const std::function<void(const State&)> &,但是我發(fā)現(xiàn)這里每次構(gòu)造 std::function<void(const State&)> 對象都會分配一次內(nèi)存,似乎有些不值。因此在現(xiàn)在的實現(xiàn)中 curr.move() 是個函數(shù)模板,這樣就能自動匹配lambda參數(shù)(通常是個 struct 對象),省去了 std::function的內(nèi)存分配。

本文完整的代碼見 https://github.com/chenshuo/recipes/…/puzzle/huarong.cc,需用 GCC 4.7 編譯,求解圖 1 的題目的耗時約幾十毫秒。

練習(xí):修改程序,打印每一步移動棋子的情況。

原文鏈接:http://coolshell.cn/articles/10476.html

責(zé)任編輯:陳四芳 來源: 酷殼網(wǎng)
相關(guān)推薦

2021-11-02 14:55:42

鴻蒙HarmonyOS應(yīng)用

2012-11-04 14:54:24

2021-10-09 14:49:50

鴻蒙HarmonyOS應(yīng)用

2021-08-25 09:54:51

鴻蒙HarmonyOS應(yīng)用

2017-09-25 16:55:35

2021-10-22 19:41:01

鴻蒙HarmonyOS應(yīng)用

2023-09-22 22:27:54

autoC++11

2024-05-29 13:21:21

2020-12-22 11:20:36

鴻蒙HarmonyOS游戲

2020-12-11 12:27:35

鴻蒙HarmonyOS

2020-06-01 21:07:33

C11C++11內(nèi)存

2012-05-17 09:26:43

MapReduce

2012-09-24 01:01:49

NginxNginx性能Web服務(wù)器

2009-07-16 13:03:05

ibatis resu

2013-12-23 09:48:43

C++鎖定模式

2024-02-21 23:43:11

C++11C++開發(fā)

2013-09-25 14:20:46

2013-05-30 00:49:36

C++11C++條件變量

2013-07-29 11:11:33

C++C++11

2021-06-11 10:53:40

Folly組件開發(fā)
點贊
收藏

51CTO技術(shù)棧公眾號