# APCS實作題2016年3月第1題:成績指標
> 第1版:2023年2月7日
> 第2版:2023年6月6日,加上使用氣泡排序法的程式碼
> 作者:王一哲
> 題目來源:[2016年3月5日實作題第1題](https://apcs.csie.ntnu.edu.tw/wp-content/uploads/2020/10/APCS-%E5%AF%A6%E4%BD%9C%E9%A1%8C-2016.03.05.pdf)
> [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=b964)
<br />
## 題目
### 問題描述
一次考試中,於所有及格學生中獲取最低分數者最為幸運,反之,於所有不及格同學中,獲取最高分數者,可以說是最為不幸,而此二種分數,可以視為成績指標。
請你設計一支程式,讀入全班成績(人數不固定),請對所有分數進行排序,並分別找出不及格中最高分數,以及及格中最低分數。
當找不到最低及格分數,表示對於本次考試而言,這是一個不幸之班級,此時請你印出:「worst case」;反之,當找不到最高不及格分數時,請你印出「best case」。
註:假設及格分數為 60,每筆測資皆為 0~100 間整數,且筆數未定。
<br />
### 輸入格式
第一行輸入學生人數,第二行為各學生分數(0~100 間),分數與分數之間以一個空白間格。每一筆測資的學生人數為 1~20 的整數。
<br />
### 輸出格式
每筆測資輸出三行。
第一行由小而大印出所有成績,兩數字之間以一個空白間格,最後一個數字後無空白;
第二行印出最高不及格分數,如果全數及格時,於此行印出 best case;
第三行印出最低及格分數,當全數不及格時,於此行印出 worst case。
<br />
### 範例一:輸入
```
10
0 11 22 33 55 66 77 99 88 44
```
### 範例一:正確輸出
```
0 11 22 33 44 55 66 77 88 99
55
66
```
(說明)不及格分數最高為 55,及格分數最低為 66。
<br />
### 範例二:輸入
```
1
13
```
### 範例二:正確輸出
```
13
13
worst case
```
(說明)由於找不到最低及格分,因此第三行須印出「worst case」。
<br />
### 範例三:輸入
```
2
73 65
```
### 範例三:正確輸出
```
65 73
best case
65
```
(說明)由於找不到不及格分,因此第二行須印出「best case」。
<br />
### 評分說明
輸入包含若干筆測試資料,每一筆測試資料的執行時間限制(time limit)均為 2 秒,依正確通過測資筆數給分。
<br />
## Python 程式碼
### 方法1,使用氣泡排序法
```python=
def bubble(data):
num = len(data)
for i in range(num-1):
for k in range(num-i-1):
if data[k] > data[k+1]:
data[k], data[k+1] = data[k+1], data[k]
return data
N = int(input()) # 輸入學生人數 (1 ~ 20)
scores = list(map(int, input().split())) # 輸入分數,並用半型空格分隔 (1 ~ 100)
scores = bubble(scores) # 使用氣泡排序法由小到大排序
high, low = -1, 101
# 第一行:印出由小到大排列後的成績,並用半型空格分隔
for i in range(N):
if i < N-1: print(scores[i], end=" ")
else: print(scores[i])
# 以上2行可以合併為 print(scores[i], end="\n" if i == N-1 else " ")
if scores[i] < 60 and scores[i] > high: high = scores[i]
if scores[i] >= 60 and scores[i] < low: low = scores[i]
# 第二行:印出最高不及格分數,如果全數及格時,於此行印出 best case
if high != -1: print(high)
else: print("best case")
# 第三行:印出最低及格分數,當全數不及格時,於此行印出 worst case
if low != 101: print(low)
else: print("worst case")
```
<br />
1. 第1 ~ 7行:自訂氣泡排序法函式 bubble,由小到大排序分數。
2. 於 ZeroJudge 測試結果,花費時間約為 27 ms,使用記憶體最多約為 3.4 MB。
<br />
氣泡排序法有兩層 for 迴圈,運作時每次會取相鄰的兩個元素比較大小,如果要由小到大排序,當左側元素大於右側元素時,將兩個元素的位置交換,當外層的 for 迴圈第一次運作完畢時,最大的元素會被移到最右側;外層的 for 迴圈第二次運作時,就不需要比較最右側的元素。假設串列內容為 \[6, 5, 4, 3, 2, 1\],如果要使用氣泡排序法將資料由小到大排序,函式運作每次運作時i、j的值及串列的內容如下:
1. i = 0
j = 0: [5, 6, 4, 3, 2, 1]
j = 1: [5, 4, 6, 3, 2, 1]
j = 2: [5, 4, 3, 6, 2, 1]
j = 3: [5, 4, 3, 2, 6, 1]
j = 4: [5, 4, 3, 2, 1, 6]
2. i = 1
j = 0: [4, 5, 3, 2, 1, 6]
j = 1: [4, 3, 5, 2, 1, 6]
j = 2: [4, 3, 2, 5, 1, 6]
j = 3: [4, 3, 2, 1, 5, 6]
3. i = 2
j = 0: [3, 4, 2, 1, 5, 6]
j = 1: [3, 2, 4, 1, 5, 6]
j = 2: [3, 2, 1, 4, 5, 6]
4. i = 3
j = 0: [2, 3, 1, 4, 5, 6]
j = 1: [2, 1, 3, 4, 5, 6]
5. i = 4, j = 0: [1, 2, 3, 4, 5, 6]
<br /><br />
### 方法2,使用 sort 排序
```python=
N = int(input()) # 輸入學生人數 (1 ~ 20)
scores = list(map(int, input().split())) # 輸入分數,並用半型空格分隔 (1 ~ 100)
scores.sort() # 預設為由小到大,若要由大到小則要加上 reverse = True
high, low = -1, 101
# 第一行:印出由小到大排列後的成績,並用半型空格分隔
for i in range(N):
if i < N-1: print(scores[i], end=" ")
else: print(scores[i])
# 以上2行可以合併為 print(scores[i], end="\n" if i == N-1 else " ")
if scores[i] < 60 and scores[i] > high: high = scores[i]
if scores[i] >= 60 and scores[i] < low: low = scores[i]
# 第二行:印出最高不及格分數,如果全數及格時,於此行印出 best case
if high != -1: print(high)
else: print("best case")
# 第三行:印出最低及格分數,當全數不及格時,於此行印出 worst case
if low != 101: print(low)
else: print("worst case")
```
<br />
1. 第3行:使用 Python 內建的 sort 工具排序,效率優於氣泡排序法。
2. 於 ZeroJudge 測試結果,花費時間約為 20 ms,使用記憶體最多約為 3.3 MB。
<br /><br />
## C++ 程式碼
### 方法1,使用氣泡排序法
```cpp=
#include <iostream>
using namespace std;
// 印出陣列用的自訂函式
void printA(int *a, int s) {
for(int i=0; i<s; i++) {
if(i < s-1) cout << a[i] << " ";
else cout << a[i] << endl;
// 以上2行可以合併為 cout << a[i] << " \n"[i == s-1];
}
}
// 氣泡排序法
void bubble(int data[], int num) {
int t;
for(int i=0; i<num-1; i++) {
for(int j=0; j<num-i-1; j++) {
if(data[j] > data[j+1]) {
t = data[j];
data[j] = data[j+1];
data[j+1] = t;
}
}
}
}
int main(int argc, char* argv[]) {
int n, high = -1, low = 101, scores[20] = {};
cin >> n; // 讀取資料
for(int i=0; i<n; i++) cin >> scores[i];
bubble(scores, n); // 由小到大排序
// 找出最高不及格分數
for(int i=0; i<n; i++) {
if(scores[i] < 60) {
high = scores[i];
} else {
break;
}
}
// 找出最低及格分數
for(int i=n-1; i>=0; i--) {
if(scores[i] >= 60) {
low = scores[i];
} else {
break;
}
}
// 印出排序後的成績
printA(scores, n);
// 印出最高不及格分數,若無則印出 best case
if(high != -1) {
cout << high << endl;
} else {
cout << "best case" << endl;
}
// 印出最低及格分數,若無則印出 worst case
if(low != 101) {
cout << low << endl;
} else {
cout << "worst case" << endl;
}
return 0;
}
```
<br />
1. 第12 ~ 24行:自訂函式,使用氣泡排序法由小到大排序資料。
2. 於 ZeroJudge 測試結果,花費時間約為 2 ms,使用記憶體最多,為 324 KB。
<br /><br />
### 方法2,使用 STL sort 工具排序
```cpp=
#include <iostream>
#include <algorithm>
using namespace std;
// 印出陣列用的自訂函式
void printA(int *a, int s) {
for(int i=0; i<s; i++) {
if(i < s-1) cout << a[i] << " ";
else cout << a[i] << endl;
// 以上2行可以合併為 cout << a[i] << " \n"[i == s-1];
}
}
// 由小到大排序用的比較方式
bool cmp(int a, int b) {
return a < b;
}
int main(int argc, char* argv[]) {
int n, high = -1, low = 101, scores[20] = {};
cin >> n; // 讀取資料
for(int i=0; i<n; i++) cin >> scores[i];
sort(scores, scores+n, cmp); // 由小到大排序
// 找出最高不及格分數
for(int i=0; i<n; i++) {
if(scores[i] < 60) {
high = scores[i];
} else {
break;
}
}
// 找出最低及格分數
for(int i=n-1; i>=0; i--) {
if(scores[i] >= 60) {
low = scores[i];
} else {
break;
}
}
// 印出排序後的成績
printA(scores, n);
// 印出最高不及格分數,若無則印出 best case
if(high != -1) {
cout << high << endl;
} else {
cout << "best case" << endl;
}
// 印出最低及格分數,若無則印出 worst case
if(low != 101) {
cout << low << endl;
} else {
cout << "worst case" << endl;
}
return 0;
}
```
<br />
1. 使用 STL sort 工具排序,因為預設為由小到大排序,可以刪除第15 ~ 17行,第25行改為 **sort(scores, scores+n);** 。
2. 於 ZeroJudge 測試結果,花費時間約為 3 ms,使用記憶體最多,為 324 KB。
<br /><br />
---
###### tags:`APCS`、`Python`、`C++`