【個人筆記】C++ ZeroJudge 基礎題庫解題(純練習) - part 1
【個人筆記】C++ ZeroJudge 基礎題庫解題(純練習) - part 1
a003.:https://zerojudge.tw/ShowProblem?problemid=a003
難度:☆☆☆☆☆
基本IO、條件判斷、四則運算
1 |
|
a004.:https://zerojudge.tw/ShowProblem?problemid=a004
難度:★☆☆☆☆
遇到需要持續輸入的迴圈,在 CPP 中使用 while (cin >> a)。
若將 while 改成 while (true),然後 cin 放裡面,會造成 TLE(Time Limit Exceed)時間超過限制。
使用 while (cin >> a) 可避免此情形發生,這行的意義為「迴圈會持續執行,直到 cin >> year 失敗為止」。
若輸入有效的整數時,條件為 true,迴圈繼續執行;若輸入了非整數,則 cin 錯誤,條件為 false,迴圈結束。
1 |
|
a005.:https://zerojudge.tw/ShowProblem?problemid=a005
難度:★★☆☆☆
雙層迴圈、條件判斷、邏輯應用。
1 |
|
a009.:https://zerojudge.tw/ShowProblem?problemid=a009
難度:★★☆☆☆
題目敘述在講的就是凱薩密碼(Caesar Cipher),要找 K(位移數),可能需要參照一下 ASCII code。
註:其實也不用參照,只要透過程式的 char() 轉整數去相減就好了。

Source:https://shihyu.github.io/books/apas01.html
然後題目是叫你自己去範例輸出輸入找 K,我們只要看第一個字元就好了:
1 | 範例輸入: |
1 | 範例輸出: |
可發現字元 '1'、字元 '*' 兩個的 ASCII Code DEC(十進位) 相差 7(49-42),所以 K 是 7。
然後就可以打 code 了:
1 |
|
為何不用 cin.get(char)?
cin.get(char) 只能一個一個去讀字元,而 getline(cin, string) 可以讀完整行字串。
另外 cin.get(char) 會保留 new-line 跳脫字元(\n)在輸入流中,若下次再次讀取,可能會讀到 \n。
getline(cin, string) 可以讀完整行字串,直到遇到 \n 為止。他會把整行字串存在 string 物件裡面,不會自行將 \n 包含在內。
總之 cin.get(char) 有可能會遇到無限迴圈的情形,但另一個不會。
那是不是看起來 cin.get(char) 比較沒啥屁用?錯。
:::successcin.get(char) 使用情形:
- 讀逐個字元
- 保留
\n - 處理跳脫字元
- 限制輸入長度:
cin.get(char array, size)像是可控制陣列長度。
:::
:::successgetline() 使用情形:
- 需忽略
\n - 有空格的字串
:::
a010.:https://zerojudge.tw/ShowProblem?problemid=a010
難度:★★★★☆
1 |
|
程式碼當中用到 C++ map 容器,可直接將其視為 Python 中的字典。
要宣告一個 map 容器,如下:
1 | std::map<key_type, value_type> myMap; |
key_type:鍵的型態。
value_type:值的型態。
插入元素:
1 | myMap[key] = value; |
存取元素:
1 | value = myMap[key]; |
遍歷 Map:
1 | for (std::map<key_type, value_type>::iterator it = myMap.begin(); it != myMap.end(); ++it) { |
來源:https://www.runoob.com/cplusplus/cpp-libs-map.html
:::success
在此使用 Map 是為了方便計算跟儲存質因數(當Key)、次方數(當Value)。
:::
a013.:https://zerojudge.tw/ShowProblem?problemid=a013
難度:★★★★★
1 |
|
:::successstring s v.s. string &s v.s. const string &s:
三種不同函數傳遞方式各有不同:
string s:傳值呼叫,效能差,如果資料量小可這樣做。string &s:傳參考呼叫,效能略勝上述。另外要注意不能傳遞字面常數(const char*),因為此時函數傳遞方式是可被修改的,不相通。const string &s:不能修改,但三者當中效能最好,反正就是可讀不能改,符合上述競程題目需求。
:::
另外在函數 int R_T_I(const string &s) 當中,採用從右至左遍歷的解題思路。
因為在羅馬數字的規則下,「大數在前小數在後」代表加法 (如 VI = 6);「小數在前大數在後」代表減法 (如 IV = 4)。
所以這樣的作法可以比較好去判斷加減法的部分,以求確切的十進位數字。
最後輸出時,根據題目輸出要求,所以還是要把數字變回去羅馬數字,那這支程式碼就定義了函數 string I_T_R(int num)。
此函數使用到了 pair 容器,需要使用此標頭檔 #include <utility> 引入。(不過我們用了萬用標頭檔所以不用手動引入)
以下是有關於 pair 的簡介:
建立一個 myPair 物件:
1 | // 此行意義為 "將整數與字串關聯在一起" |
看到物件就會想到類別,對,沒錯,pair 本身是類別。而 pair 內部有兩個 public 的 member:first、second,可用於存取 pair 的值。
如下:
1 |
|
輸出結果:
1 | 123 |
回到正題,在函數 string I_T_R(int num) 中,為何使用 pair 容器而不是 map?
:::success
因為 map 內的鍵值對會自動做升序(由小到大遞增排序),並不符合羅馬數字的「減法規則」,而使用 pair 則不會更動順序,能自行調整,所以便使用 pair。
:::
最後
1 | string result; |
這個部分,至於使用到 const auto &[value, symbol] 的目的,在於這東西是固定不動的(裡面是既定的羅馬數字對應十進位數字),不會被修改,所以給他加上 const。還有個好處就是帶來效能提升跟避免不必要的錯誤(如被修改到)。
另外加上 & 是因為 range-based for 內容物需要被修改到。




