---
# System prepended metadata

title: APCS 小菜雞費曼自學紀錄
tags: [APCS, Cpp, 自學]

---

# 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`（較佳）換行

