文章目錄
- 💯前言
- 💯題目描述
- 游戲規則:
- 輸入格式:
- 輸出格式:
- 輸入輸出樣例:
- 解題分析與實現
- 💯我的做法
- 實現邏輯
- 優點與不足
- 💯老師的做法
- 實現邏輯
- 優點與不足
- 💯對比分析
- 💯優化與擴展
- 優化代碼實現
- 優化后的優點
- 擴展場景
- 💯總結
💯前言
- "石頭剪子布"是一種經典游戲,它不僅規則簡單,還能引發復雜的編程邏輯討論。在本篇文章中,我們將以一道 C++ 的編程題為例,深入剖析解題的思路、優化方法,以及延伸出的編程概念。通過對比兩種實現方式(我的實現和老師的實現),結合擴展性和代碼優化的思路,幫助讀者全面理解這一題目及其潛在的編程技巧。
C++ 參考手冊
💯題目描述
B2112 石頭剪子布
石頭剪子布,是一種猜拳游戲,起源于中國,然后傳到日本,朝鮮等地,隨著亞歐貿易的不斷發展它傳到西歐,到了現代化逐漸國際化的世界中。簡單明了的規則,使得石頭剪子布沒有任何知識和規則漏洞可鉆,單次玩法讓比賽公平,容易且充滿心理博弈,使得石頭剪子布這個古老的游戲同時用于“意外”與“技術”兩種特性,深受世界人民喜愛。
游戲規則:
石頭剪子布,布包石頭,石頭砸剪刀,剪刀剪布。
現在,需要你寫一個程序來判斷石頭剪子布游戲的結果。
輸入格式:
第一行是一個整數 N,表示一共進行 N 次游戲。1 <= N <= 100。
接下來 N 行的每一行包括兩個字符串,表示游戲參與者 Player1,Player2 的選擇(石頭、剪刀或者布):S1,S2。
字符串之間以空格隔開 S1 S2 只可能取值在 [Rock, Scissors, Paper](大小寫敏感)中。
輸出格式:
輸出包括 N 行,每一行對應一個勝利者(Player1 或者 Player2),或者游戲出現平局,則輸出 Tie。
輸入輸出樣例:
輸入 #1
3
Rock Scissors
Paper Paper
Rock Paper
輸出 #1
Player1
Tie
Player2
解題分析與實現
接下來,我們將從兩個實現方式出發:我的做法、老師的做法,逐步剖析解決問題的不同方式,最后對比兩種實現,并延展出優化和擴展思路。
💯我的做法
以下是我的代碼實現:
#include <iostream>
#include <string>
using namespace std;int main()
{ int n;cin >> n;string s1, s2;for(int i = 0; i < n; i++){cin >> s1 >> s2;if(s1 == "Rock"){if(s2 == "Scissors")cout << "Player1" << endl;else if(s2 == "Paper")cout << "Player2" << endl;elsecout << "Tie" << endl;}else if(s1 == "Scissors") {if(s2 == "Scissors")cout << "Tie" << endl;else if(s2 == "Paper")cout << "Player1" << endl;elsecout << "Player2" << endl;}else{if(s2 == "Scissors")cout << "Player2" << endl;else if(s2 == "Paper")cout << "Tie" << endl;elsecout << "Player1" << endl;}}return 0;
}
實現邏輯
-
輸入處理:讀取整數
n
,表示對局次數,循環讀取Player1
和Player2
的選擇。 -
判斷規則:
- 通過嵌套的
if-else
分支,根據Player1
的選擇 (Rock
,Scissors
,Paper
) 逐步判斷Player2
的選擇,從而決定勝負。 - 平局條件 (
s1 == s2
) 被單獨處理。
- 通過嵌套的
-
逐行輸出:根據每場比賽的結果,輸出 “Player1”、“Player2” 或 “Tie”。
優點與不足
-
優點:
- 邏輯清晰,適合初學者。
- 每種情況都顯式列出,容易理解。
-
不足:
- 冗余邏輯:大量的條件分支導致代碼較為臃腫。
- 可擴展性差:如果加入新規則(如 “Lizard” 和 “Spock”),代碼需要大規模改動。
💯老師的做法
以下是老師的代碼實現:
#include <iostream>
#include <string>
using namespace std;int main()
{int n = 0;cin >> n;int i = 0;string s1;string s2;while(n--){cin >> s1;cin >> s2;if(s1 == s2)cout << "Tie" << endl;else if (s1 == "Rock" && s2 == "Scissors")cout << "Player1" << endl;else if (s1 == "Scissors" && s2 == "Paper")cout << "Player1" << endl;else if (s1 == "Paper" && s2 == "Rock")cout << "Player1" << endl;elsecout << "Player2" << endl;} return 0;
}
實現邏輯
- 使用
while
循環減少代碼結構的復雜性,每次循環中處理一場比賽。 - 平局條件 (
s1 == s2
) 優先判斷,避免進入更多分支。 Player1
的勝利條件通過顯式列舉的方式判斷。- 如果上述條件都不滿足,則默認為
Player2
勝出。
優點與不足
-
優點:
- 代碼結構簡潔,分支層次少。
- 平局條件優先處理,邏輯順暢。
-
不足:
- 同樣存在條件分支冗余問題。
- 可擴展性不足。
💯對比分析
對比點 | 我的做法 | 老師的做法 |
---|---|---|
代碼結構 | 使用嵌套 if-else ,分支較多 | 使用單層 if-else ,邏輯更清晰 |
冗余程度 | 條件分支更多,顯式判斷所有情況 | 條件分支較少,但仍有顯式判斷 |
可擴展性 | 新規則需要大規模修改 | 新規則需要大規模修改 |
適合初學者 | 邏輯直觀,適合初學者練習 | 邏輯簡化,更適合掌握基本結構的學生 |
💯優化與擴展
為了進一步優化和擴展,我們可以使用數據結構來簡化邏輯,提高可擴展性。
優化代碼實現
通過使用 map
存儲勝負規則,可以避免顯式列舉所有情況。
#include <iostream>
#include <string>
#include <map>
using namespace std;int main() {int n;cin >> n;// 定義勝負規則map<string, string> winRules = {{"Rock", "Scissors"},{"Scissors", "Paper"},{"Paper", "Rock"}};string s1, s2;while (n--) {cin >> s1 >> s2;if (s1 == s2) {cout << "Tie" << endl;} else if (winRules[s1] == s2) {cout << "Player1" << endl;} else {cout << "Player2" << endl;}}return 0;
}
優化后的優點
- 邏輯簡化:通過查表判斷勝負,避免嵌套的
if-else
。 - 易擴展性:增加新規則只需擴展
map
,無需修改核心邏輯。 - 代碼簡潔:主邏輯更清晰,減少冗余判斷。
擴展場景
- 多種新規則:如引入 “Lizard” 和 “Spock”。
- 支持多輪游戲:記錄每場比賽的勝利者,并統計最終勝負結果。
- 本地化支持:使用多語言輸出結果。
💯總結
通過這道題目,我們探討了兩種不同的解法,以及如何優化代碼邏輯。我的實現和老師的實現都能正確解決問題,但在簡潔性和擴展性上存在一定不足。優化后的代碼通過數據結構簡化了邏輯,提高了代碼的可維護性和可擴展性。
編程不僅僅是實現功能,還在于如何更優雅、更高效地實現。本題為我們提供了一個非常好的練習機會,希望讀者在掌握了這些方法后,能更深入地理解編程的本質和技巧。
1. 理解C++的基礎
學習重點:
- 掌握基本語法:
- 學會聲明變量、條件語句、循環、函數等核心語法。
- 掌握數組、指針、引用等基礎知識。
- 熟悉標準輸入輸出:
- 掌握
cin
和cout
的用法。 - 理解格式化輸出,例如
std::setw
和std::fixed
。
- 掌握
- 記住編譯器的角色:
- 理解源代碼如何通過編譯器轉換為可執行程序,選擇一款好的IDE(如Visual Studio、Clion、VSCode)。
建議:用大量小程序練習這些基礎語法,比如寫一個計算器、模擬猜數字游戲等。
2. 深入學習C++的特性
學習重點:
- 面向對象編程(OOP):
- 理解類和對象,熟悉如何定義類、成員變量和成員函數。
- 掌握封裝、繼承、多態三大核心特性。
- 內存管理:
- 理解指針的用法,掌握動態內存分配(
new
和delete
)。 - 學習如何避免內存泄漏,熟悉智能指針(如
std::unique_ptr
和std::shared_ptr
)。
- 理解指針的用法,掌握動態內存分配(
- 標準模板庫(STL):
- 熟悉常用的容器(如
vector
、map
、set
)和算法(如sort
、find
)。 - 掌握迭代器的用法。
- 熟悉常用的容器(如
- 異常處理:
- 學習使用
try-catch
塊處理異常。 - 理解異常的用途以及如何設計健壯的代碼。
- 學習使用
建議:嘗試開發一個小型項目,比如一個學生管理系統,綜合應用類、STL、指針和動態內存分配。
3. 掌握進階內容
學習重點:
- 模板:
- 理解函數模板和類模板,掌握泛型編程思想。
- 學習模板特化和模板元編程的基本概念。
- 多線程與并發:
- 學習 C++11 提供的多線程支持(如
std::thread
)。 - 熟悉互斥鎖(
std::mutex
)和條件變量(std::condition_variable
)。
- 學習 C++11 提供的多線程支持(如
- C++與C的兼容性:
- 學習如何在C++中使用C語言代碼,理解C和C++的區別。
- 掌握C風格字符串(
char[]
)和C++字符串(std::string
)的轉換。
建議:在這一階段,可以挑戰更復雜的項目,比如開發一個小型的HTTP服務器,學習網絡編程并結合多線程。
4. 學習資源與實踐方法
學習資源:
- 書籍:
- 《C++ Primer》:非常適合初學者的經典書籍。
- 《Effective C++》:進階學習C++最佳實踐的指南。
- 《The C++ Programming Language》:Bjarne Stroustrup(C++之父)的權威著作。
- 在線課程:
- Coursera 上的 C++ 編程課程。
- YouTube 上免費的 C++ 系列教程。
- 社區與文檔:
- 參與C++相關的論壇(如CSDN、Stack Overflow)。
- 閱讀官方文檔(https://en.cppreference.com)。
實踐方法:
- 多寫代碼,多調試:
- 每學一個概念后,寫至少兩個示例代碼并進行調試。
- 做小項目:
- 從簡單的控制臺程序開始,比如文件讀寫、計算器、小游戲等。
- 慢慢過渡到圖形界面或網絡程序開發。
- 閱讀他人代碼:
- 閱讀開源項目的代碼,理解優秀代碼的設計思路。
- 參加編程比賽:
- 比如 LeetCode 或 Codeforces,可以幫助你提升算法能力和C++的熟練度。
5. 保持耐心與興趣
學習C++可能會面臨以下困難:
- 復雜的語法:如模板、智能指針、多線程等。
- 調試困難:指針錯誤、內存泄漏、未定義行為可能讓人頭疼。
如何應對:
- 將大問題拆解成小問題,逐步解決。
- 不斷重復基礎知識,以加深理解。
- 保持興趣,嘗試一些有趣的項目,比如寫一個游戲、制作一個簡單的圖形程序。
小結
學習C++需要一個循序漸進的過程,從基礎語法到面向對象編程,再到進階的模板和并發編程,每一步都需要耐心和實踐。通過充分利用學習資源、進行大量編碼練習,以及挑戰實際項目,你一定可以成為C++的高手。記住,學習的核心在于理解,而非死記硬背。
祝你學有所成,享受C++編程的樂趣!