語法書 / AA 競程語法書 上冊 / 第五單元 / OJ 如何判斷你的程式

5.1 OJ 如何判斷你的程式

自己電腦上測試通過 ≠ 程式完全正確。理解 OJ 的評測原理,才能知道自己的程式在哪裡出問題。

核心原理

線上評測系統(Online Judge,簡稱 OJ)的判定方式很簡單:

系統裡存放著一批隱藏測試資料(通常 50-200 組不等),OJ 會把你的程式對著每一組測資跑一遍,只要有任何一組答錯,整題就判為不正確。只有全部答對,才是通過(AC)。

實例:AACPOJ「A+B 問題 1」

以我們 AACPOJ 上的入門題 A+B 問題 1 為例:

題目資訊區

題目名稱:A+B 問題 1

題目描述 給你兩個整數 ab,請輸出它們的和 a+b

輸入格式 輸入只有一行,包含兩個整數 ab0 \le a, b \le 10)。

輸出格式 輸出一個整數,代表 a+b

範例輸入

1 2

範例輸出

3

時間限制 0.5 秒

記憶體限制 262144 KiB

OJ 怎麼評測的

題目頁面上看得到的範例(1 23)只是其中一組測資。系統背後還藏著一批你看不到的隱藏測資,例如:

  • 10 10 → 應該輸出 20
  • 0 0 → 應該輸出 0
  • 0 10 → 應該輸出 10
  • ...(還有其他組合)

你的程式必須對所有這些隱藏測資都答對,才算通過。範例(1 23)通常也被放進隱藏測資裡,是眾多測資中的一組。

理解隱藏測資的概念很重要,因為它解釋了為什麼「我的程式在自己電腦跑對了,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 10200 000 1010……但這支程式無論輸入是什麼都只會印 3,除了範例那組以外全都答錯,整題判 WA(答案錯誤)

這正是隱藏測資存在的意義:它擋掉這種「只湊出範例答案、根本沒真的在算」的程式。通過範例,不等於 AC。 提交前,別只用範例測——多想幾種它沒測到的情況。

輸出比對:嚴格與非嚴格

OJ 比對「你的輸出」和「標準答案」時,嚴謹程度依題目設定分成兩種:

模式 規則
嚴格比對 輸出必須一字不差:相鄰項目之間恰一個空白、行末不能有多餘空白、最後要換行
非嚴格比對 忽略同一行內空白「數量」的差異、行末多餘空白、檔案結尾有沒有換行;但有意義的換行仍然要對——該在同一行的內容還是得在同一行

題目沒特別說明時,保險的做法是照嚴格比對的標準輸出——嚴格合格的輸出,在非嚴格底下也一定通過。

其實非嚴格的寬鬆程度還會因評測系統而異,有些系統更寬鬆(例如 Codeforces 的預設比對連換行都不計較);但這不影響你的做法——只要照嚴格標準輸出,在任何系統都會通過,所以你不必去記這些差異。

以「把 1n 輸出在同一行、以空白隔開」為例,嚴格比對下最常用的寫法是「不是第一個,就先補一個空白」:

for (int i = 1; i <= n; i++) {
    if (i > 1) cout << " ";   // 不是第一個 → 先補一個空白
    cout << i;
}
cout << "\n";                 // 行末剛好沒有多餘空白,最後補換行