# APCS 小菜雞費曼自學紀錄 > 目標:掌握 C++ 基本語法、vector、排序、分類 ## 戳記 >[!Caution]筆者在能力進步後又改寫了一個新版的:)[APCS 小菜雞費曼自學紀錄](/PpNIwwQnRLmpYYsNOTF5ww) > [time=Wed, Aug 27, 2025 3:04 PM][name=HuanJay Lin (口艸田)] > [[zerojudge question link](https://zerojudge.tw/ShowProblem?problemid=b964)] > 使用語言:C++ ## 題目描述 > b964. 1. 成績指標 ### APCS 201603-1 成績指標 一次考試中,於所有及格學生中獲取最低分數者最為幸運,反之,於所有不及格同學中,獲取最高分數者,可以說是最為不幸,而此二種分數,可以視為成績指標。 請你設計一支程式,讀入全班成績(人數不固定),請對所有分數進行排序,並分別找出不及格中最高分數,以及及格中最低分數。 當找不到最低及格分數,表示對於本次考試而言,這是一個不幸之班級,此時請你印出「worst case」;反之,當找不到最高不及格分數時,請你印出「best case」。 ( 註:假設及格分數為 60 )。 ### 輸入說明 第一行輸入學生人數,第二行為各學生分數(0~100 間),分數與分數之間以一個空白間格。學生人數為 1~20 的整數。 ### 輸出說明 輸出三行。 第一行由小而大印出所有成績,兩數字之間以一個空白間格,最後一個數字後無空白; 第二行印出**最高不及格分數**,如果全數及格時,於此行印出 best case ; 第三行印出**最低及格分數**,如果全數不及格時,於此行印出 worst case 。 ## 解題歷程 ### 基本分析(intput/output) 1. 基本輸入兩個內容 - 學生數,令StudentNum - 個別成績,令scores[] ,意即定義一個 vector 或 array 2. 輸出 1. 學生成績的升冪排列(這裡有使用 sort 的味道) 2. cout **最高不及格分數** or **best case(當情況為 all pass 時)** 3. cout **最低及格分數** or **worse case(當情況為 all fail 時)** 由此我們可以開始==從「結果」反推邏輯「過程」==。 ### 解題思路 > 1. 先分析輸入輸出 > 2. 決定使用資料結構(陣列、vector 等) > 3. 分類、排序、迴圈等核心邏輯 > 4. 特殊情況(best/worst case)處理 依照題目,我們可以非常輕鬆的先寫出下列程式: ```cpp= #include <iostream> using namespace std; int main(){ int StudentNum; cin >> StudentNum; //... //這裡再放上vector或array } ``` 其實筆者在這裡時有點小卡關,因為距離上一次寫APCS之題目早已隔兩年之久,技巧生疏,只依稀記得流程、Cpp基本使用,所以這邊我們先來簡略複習一下這題該使用的知識、技巧。 --- #### Vector v. Array 開始前,容我先來簡單解釋一下何謂Vector以及Array好了。 ##### What is Vector? vector (向量)在 C++ 是 STL(Standard Template Library)提供的 **動態陣列**。 其有三個超棒的特性: 1. 其**大小可以動態增減(不用像陣列(Array)固定大小)** 2. **支援索引存取,像陣列一樣 v[ i ]** 3. 常用於需要分類、排序或暫存資料的場合 這裡做一個簡單示範: ```cpp= #include <vector> #include <iostream> using namespace std; int main() { vector<int> v; // 宣告空 vector「v」 v.push_back(10); // 尾端加入元素 v.push_back(20); cout << v[0] << " " << v[1] << endl; // 輸出 10 20 } ``` 我們可以觀察到幾個特性: 其一,其起始項是 [0] 。 其二,新元素加入是從尾部加進去的(因使用v.push_back(某值))。 接下來,讓我們利用幾個「宣告 vector 」的示範,使我們更認識它的特性: ```cpp= vector<int> v1; // 空 vector vector<int> v2(5); // 大小 5,初值為 0 vector<int> v3(5, 10); // 大小 5,每個元素初值為 10 vector<int> v4 = {1,2,3};// 初始化列表 ``` >[!Tip] >`v.size()` → vector 元素數量 >`v.empty()` → 是否為空 → 輸出值為 1 或 0 ##### vector 常用操作 最後,筆者將 vector 常用操作整理成表供各位參考: | 操作 | 說明 | 範例 | | -------------------------- | -------------------- | --------------------------- | | `push_back(x)` | 尾端加入元素 | `v.push_back(42);` | | `pop_back()` | 刪除最後一個元素 | `v.pop_back();` | | `v[i]` | 存取第 i 個元素(0-index) | `cout << v[0];` | | `front()` | 取第一個元素 | `cout << v.front();` | | `back()` | 取最後一個元素 | `cout << v.back();` | | `size()` | 元素數量 | `cout << v.size();` | | `empty()` | 是否為空 | `if(v.empty()) ...` | | `clear()` | 清空 vector | `v.clear();` | | `sort(v.begin(), v.end())` | 排序(需要 `<algorithm>`) | `sort(v.begin(), v.end());` | ##### What is Array? 說完比較進階的 vector 後,我們來介紹基礎款的 陣列(array)。 陣列(Array)是一種 **固定大小**的連續記憶體結構,意即其大小設定完後無法更動。 這裡先介紹一下 array 的三個特點: 1. 大小必須在宣告時指定 2. 支援索引存取(0-index) 3. 元素類型固定 筆者這裡做一個簡單範例使各位能迅速理解: ```cpp= #include <iostream> using namespace std; int main() { int arr[5]; // 宣告大小 5 的陣列 arr[0] = 10; // 指定arr[0]的初始值 arr[1] = 20; cout << arr[0] << " " << arr[1] << endl; // 輸出 10 20 } ``` 在學習 vector 後,你應該可以發現到 array 和 vector 略微相似。那麼,讓我們繼續深入觀察其「宣吿方式」: ```cpp= int a[5]; // 宣告大小 5 int b[5] = {1,2,3}; // 初始化前3個元素,其他元素為 0 int c[] = {10,20,30}; // 自動計算大小 ``` >[!Tip] >固定大小 → 陣列無法動態增加元素(需提前知道大小或設定最大值 >) ##### array 常用操作 這裡筆者一樣整理了幾項常見 arr 操作方式供各位參考: | 操作 | 說明 | 範例 | | ---- | ------------------------------ | ----------------------------------------- | | 存取元素 | 用索引存取 | `arr[0] = 5; cout << arr[0];` | | 長度 | 用 `sizeof(arr)/sizeof(arr[0])` | `int n = sizeof(arr)/sizeof(arr[0]);` | | 遍歷 | for 迴圈 | `for(int i=0;i<5;i++) cout<<arr[i]<<" ";` | | 排序 | 需 `<algorithm>` | `sort(arr, arr+5);` | #### Vector & Array 在學習完 vector 與 array 後,我們可以來做個類推與比較,讓我們對這兩種資料結構能有更深刻的印象。 >預設 矩陣為arr[],向量為 v | 特性 | 陣列 arr | 向量 vector | | ---- | ------------------ | -------------------------- | | 大小 | 固定 | 動態可增減 | | 宣告 | `int arr[5];` | `vector<int> v;` | | 存取 | `arr[i]` | `v[i]` 或 `v.at(i)` | | 新增元素 | 不行 | `v.push_back()` | | 排序 | `sort(arr, arr+n)` | `sort(v.begin(), v.end())` | | 空判斷 | `n == 0` | `v.empty()` | >[!Tip] >- Array → 適合大小固定、追求效率 >- Vector → 適合分類、大小不固定、需要方便操作 >- 排序、分類、取 front/back → vector 比 array 更直觀 >- arrary 存取速度比 vector 快 --- 在了解過後我們可以寫出下列程式: ###### vector version ```cpp= #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int StudentNum; cin >> StudentNum; vector<int> scores(StudentNum); vector<int> pass, fail; for (int i = 0; i < StudentNum; i++) { cin >> scores[i]; } //分組 for (int j = 0; j < StudentNum; j++) { if (scores[j] >= 60) { pass.push_back(scores[j]); } else { fail.push_back(scores[j]); } } sort(pass.begin(), pass.end()); sort(fail.begin( ), fail.end()); sort(scores.begin(), scores.end()); // 第一行解 for (int k = 0; k < StudentNum; k++) { cout << scores[k]; if(k != StudentNum - 1) cout << " "; } cout << endl; //第二行解 if(fail.empty()) cout << "best case" << endl; else cout << fail.back() << endl; //第三行解 if(pass.empty()) cout << "worst case" << endl; else cout << pass.front() << endl; } ``` ##### array version ```cpp= #include <iostream> #include <algorithm> using namespace std; int main() { int StudentNum; cin >> StudentNum; int scores[20]; // 最大學生數量假設 20,由題可知 int pass[20], fail[20]; int passCount = 0, failCount = 0; for (int i = 0; i < StudentNum; i++) { cin >> scores[i]; } // 分組 for (int i = 0; i < StudentNum; i++) { if (scores[i] >= 60) { pass[passCount++] = scores[i]; } else { fail[failCount++] = scores[i]; } } sort(scores, scores + StudentNum); sort(pass, pass + passCount); sort(fail, fail + failCount); // 解1 for (int i = 0; i < StudentNum; i++) { cout << scores[i]; if (i != StudentNum - 1) cout << " "; } cout << endl; // 解2 if (failCount == 0) cout << "best case" << endl; else cout << fail[failCount - 1] << endl; // 解3 if (passCount == 0) cout << "worst case" << endl; else cout << pass[0] << endl; return 0; } ``` >[!Warning]重點說明 >1. `scores[20]`、`pass[20]`、`fail[20]` → 因題目限制學生人數 ≤ 20,所以固定大小 20 即可 > 2. `passCount`、`failCount` → 為記錄每個分類的元素數量 排序時: - 陣列:`sort(arr, arr + n)` - vector:`sort(v.begin(), v.end())` >3. 取極值(最高/最低): - 陣列:`pass[0]` 或 `fail[failCount-1]` - vector:`pass.front()` 或 `fail.back()` >4. 注意每行輸出後要 `endl` 或 `\n`(較佳)換行