5.1 OJ 如何判斷你的程式
自己電腦上測試通過 ≠ 程式完全正確。理解 OJ 的評測原理,才能知道自己的程式在哪裡出問題。
¶核心原理
線上評測系統(Online Judge,簡稱 OJ)的判定方式很簡單:
系統裡存放著一批隱藏測試資料(通常 50-200 組不等),OJ 會把你的程式對著每一組測資跑一遍,只要有任何一組答錯,整題就判為不正確。只有全部答對,才是通過(AC)。
¶實例:AACPOJ「A+B 問題 1」
以我們 AACPOJ 上的入門題 A+B 問題 1 為例:
¶題目資訊區
題目名稱:A+B 問題 1
題目描述 給你兩個整數 a 和 b,請輸出它們的和 a+b。
輸入格式 輸入只有一行,包含兩個整數 a 和 b(0 \le a, b \le 10)。
輸出格式 輸出一個整數,代表 a+b。
範例輸入
1 2範例輸出
3時間限制 0.5 秒
記憶體限制 262144 KiB
¶OJ 怎麼評測的
題目頁面上看得到的範例(1 2 → 3)只是其中一組測資。系統背後還藏著一批你看不到的隱藏測資,例如:
10 10→ 應該輸出200 0→ 應該輸出00 10→ 應該輸出10- ...(還有其他組合)
你的程式必須對所有這些隱藏測資都答對,才算通過。範例(1 2 → 3)通常也被放進隱藏測資裡,是眾多測資中的一組。
理解隱藏測資的概念很重要,因為它解釋了為什麼「我的程式在自己電腦跑對了,OJ 卻判錯」:你測到的只是少數情況,OJ 會用更多你看不到的資料檢查程式。
¶一個危險的「假解」
有人看到範例的答案是 3,就想:那我乾脆不管輸入、直接印出 3 不就好了?
#include <iostream>
using namespace std;
int main() {
cout << "3" << endl; // 完全不讀輸入,直接印出 3
return 0;
}
把這支程式拿去 A+B 問題 1 試試看,你會得到很有啟發性的結果:
- 測範例(
1 2):範例的答案剛好就是3,這支程式通過了——看起來好像對了! - 正式提交:OJ 拿隱藏測資一組一組檢查——
10 10要20、0 0要0、0 10要10……但這支程式無論輸入是什麼都只會印3,除了範例那組以外全都答錯,整題判 WA(答案錯誤)。
這正是隱藏測資存在的意義:它擋掉這種「只湊出範例答案、根本沒真的在算」的程式。通過範例,不等於 AC。 提交前,別只用範例測——多想幾種它沒測到的情況。
¶輸出比對:嚴格與非嚴格
OJ 比對「你的輸出」和「標準答案」時,嚴謹程度依題目設定分成兩種:
| 模式 | 規則 |
|---|---|
| 嚴格比對 | 輸出必須一字不差:相鄰項目之間恰一個空白、行末不能有多餘空白、最後要換行 |
| 非嚴格比對 | 忽略同一行內空白「數量」的差異、行末多餘空白、檔案結尾有沒有換行;但有意義的換行仍然要對——該在同一行的內容還是得在同一行 |
題目沒特別說明時,保險的做法是照嚴格比對的標準輸出——嚴格合格的輸出,在非嚴格底下也一定通過。
其實非嚴格的寬鬆程度還會因評測系統而異,有些系統更寬鬆(例如 Codeforces 的預設比對連換行都不計較);但這不影響你的做法——只要照嚴格標準輸出,在任何系統都會通過,所以你不必去記這些差異。
以「把 1 到 n 輸出在同一行、以空白隔開」為例,嚴格比對下最常用的寫法是「不是第一個,就先補一個空白」:
for (int i = 1; i <= n; i++) {
if (i > 1) cout << " "; // 不是第一個 → 先補一個空白
cout << i;
}
cout << "\n"; // 行末剛好沒有多餘空白,最後補換行