Сегодня смотрим на довольно важную штуку, которая поможет нафармить важнейшие баллы - стресс тестирование👍
Определение
Стресс‑тестирование - это метод поиска ошибок в коде, при котором:
1. генерируются случайные тесты;
2. результаты работы двух решений сравниваются между собой.
Обычно используют:
stupid — медленное, но гарантированно корректное решение;
smart — быстрое, но потенциально ошибочное решение.
Метод особенно полезен:
1. на соревнованиях формата IOI;
2. когда есть время на отладку;
3. если уже написано решение для маленьких подгрупп данных.
Идея
Схема стресс‑теста:
1. Генератор gen создаёт случайный корректный тест.
2. Тест подаётся на вход stupid и smart.
3. Скрипт checker сравнивает результаты.
4. Если ответы различаются - тест сохраняется, выполнение останавливается.
5. Цикл повторяется заданное число раз (или вообще бесконечно).
Разберём на примере
Задача. Дан массив чисел. Необходимо найти максимальный элемент.
Решение stupid (эталонное):
int a[maxn];
void stupid() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
int ans = 1e9;
for (int i = 0; i < n; i++)
ans = max(ans, a[i]);
cout << ans;
}
Решение smart (с ошибкой):
В цикле пропущена первая ячейка массива (i = 1 вместо i = 0):
void smart() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
int ans = 1e9;
for (int i = 1; i < n; i++) // ошибка: начинаем с i = 1
ans = max(ans, a[i]);
cout << ans;
}Способы реализации
1. Самый простой подход: генератор и оба решения — функции внутри main.
int a[maxn];
int n;
int stupid() { /* ... */ }
int smart() { /* ... */ }
void gen() {
n = rand() % 10 + 1;
for (int i = 0; i < n; i++)
a[i] = rand();
}
int main() {
for (int i = 0; i < 100; i++) {
gen();
if (smart() != stupid()) {
cout << "WA" << endl;
cout << n << endl;
for (int j = 0; j < n; j++)
cout << a[j] << ' ';
break;
}
cout << "OK" << endl;
}
return 0;
}
Плюсы: быстро собрать для разового теста.
Минусы:
1. дублирование кода для разных задач;
2. нельзя использовать другие языки программирования;
3. усложнение исходного кода;
4. проблемы с глобальными переменными;
5. необходимость переключения режимов ввода.
2. Тестирование внешним скриптом
Решения и генератор лежат в отдельных файлах. Данные передаем через потоки ввода‑вывода.
Пишем питонячий скрипт (назовём его checker)
import os, sys
_, f1, f2, gen, iters = sys.argv
for i in range(int(iters)):
print('Test', i + 1)
os.system(f'python3 {gen} > test.txt')
v1 = os.popen(f'./{f1} < test.txt').read()
v2 = os.popen(f'./{f2} < test.txt').read()
if v1 != v2:
print("Failed test:")
print(open("test.txt").read())
print(f'Output of {f1}:')
print(v1)
print(f'Output of {f2}:')
print(v2)
break
Запуск (предварительно скомпилировав stupid и smart в ту же директорию, что и сам checker.py. При желании можно также прописать компиляцию прямо внутри скрипта.)
python3 checker.py stupid smart gen.py 100
@postupashki_prog