# 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`(較佳)換行