15.6 手造測資:從極端情況下手
15.1 的流程走到「尋找會錯的測資」時,範例測資常常幫不上忙——因為你的程式已經過了範例。下一步就是自己造。造測資不是亂槍打鳥,有一份固定的靈感清單:極端情況(edge cases)。錯誤特別喜歡躲在範圍的邊邊角角。
¶極端測資清單
| 造什麼 | 特別會抓到的錯 |
|---|---|
| n = 1(最小規模) | 「至少要有兩個元素」的隱藏假設、迴圈少跑或多跑一圈 |
| n = 0(若題目允許) | 空輸入的處理、除以 0 |
| 最大範圍(n 與數值都塞到上限) | 整數溢位、陣列開太小、TLE |
| 全部相同 | 「嚴格大於」與「大於等於」搞混、找第二大這類題的重複值處理 |
| 已排序/倒序 | 排序相關邏輯、「第一個」「最後一個」的方向錯誤 |
| 負數與 0(若範圍允許) | 「想當然的正數假設」——15.1 的 mn = 0 正是被全正數測資抓到的 |
| 剛好踩在邊界值(恰等於上限或下限) | < 與 <= 的差一錯誤 |
用法:對照題目的輸入範圍,把清單裡題目允許的項目逐一造出來餵程式,每一組都先手算好正確答案再比對。範圍寫 1 \le n 就不用造 n = 0——但 n = 1 一定要造,它是合法的!
¶大測資用程式造,寫進檔案
清單裡的「最大範圍」有 10^5 個數字,手打會先陣亡——讓程式代勞,直接用 14.3 的 ofstream 寫進檔案:
#include <bits/stdc++.h>
using namespace std;
int main() {
ofstream fout("big.txt"); // 把測資寫進檔案
int n = 100000; // 題目給的最大範圍
fout << n << '\n';
for (int i = 0; i < n; i++) {
fout << 1000000000 << ' '; // 全部塞上限值:順便逼出溢位
}
fout << '\n';
return 0;
}
跑完得到一個 big.txt(開頭是 100000,第二行是十萬個 10^9,本站實測產出約 1.1 MB)。接著用 14.7 的重導向把它餵給你的解答:
./a.out < big.txt
一石三鳥:答案對不對(極大值會不會溢位)、跑得快不快(拿手機計時,遠超時限就是 TLE 預定)、會不會當掉(陣列夠不夠大)。想在程式內開檔也可以,14.4 的 freopen 加一行即可。
動手試試看:拿 15.1 的「最大值減最小值」錯誤程式當靶子,把清單裡的每一項各造一組測資餵它,記錄哪幾項能抓到 mn = 0 的 bug(提示:至少有兩項抓得到)。這個練習會讓你對「哪種錯躲在哪種邊界」長出直覺。