Командная работа (решение олимпиад прошлых лет)
Работа с архивами олимпиад
Архивы с прошедшими олимпиадами (условия, тесты, решения) можно найти на сайтах (список неполный).
- На русском языке:
- http://neerc.ifmo.ru/school/archive/index.html - архив материалов олимпиад от Андрея Станкевича. В том числе: http://neerc.ifmo.ru/school/archive/2010-2011.html#regional - областные (региональные) туры.
- http://olympiads.ru - архивы Московских (в основном) олимпиад по информатике.
- http://byoi.narod.ru/ - белорусские олимпиады по информатике (где-то до 2005 года)
- ...
- На английском языке:
- ...
Список будет пополняться ;)
Содержимое архива
Задача, как правило, содержит тесты, решения жюри, условия и чекер (checker) - программу для проверки ответа на однин тест.
1. Компиляция чекера
Чекер (checker) проверяет ответ участника на одном тесте. Он получает три файла: входной файл теста, вывод программы участника и эталонный ответ жюри. Имена файлов передаются в командной строке в этом порядке: check input.txt output.txt answer.txt. Вердикт чекер сообщает кодом возврата (соглашение библиотеки testlib, коды по умолчанию):
- 0 - OK: ответ верный;
- 1 - WA (Wrong Answer): ответ неверный;
- 2 - PE (Presentation Error): ответ верен по существу, но оформлен неверно, например, после ответа есть лишний текст;
- 3 - FAIL: чекер или жюри не могут проверить тест, например, эталонный ответ не равен A+B. Это ошибка организаторов, а не участника.
Чекер обычно пишут с библиотекой testlib.h (Mike Mirzayanov), см. раздел «Чекер на С/C++» ниже. Ниже приведён пример чекера для задачи A+B, который обходится без testlib.h и собирается без дополнительных файлов: он сам читает три файла и возвращает те же коды.
Для компиляции можно использовать строку вида:
g++ -std=c++17 -O2 -Wall check.cpp -o check.exe
Запуск: check.exe input.txt output.txt answer.txt (в Linux: ./check.exe input.txt output.txt answer.txt). Код возврата выводится командой
echo %errorlevel% в Windows или echo $? в Linux.
Если аргументов командной строки не три, пример печатает четыре встроенных случая, по одному на каждый код возврата.
Реализация на C++
#include <charconv>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <system_error>
// Коды возврата чекера (соглашение testlib по умолчанию).
enum Verdict { OK = 0, WA = 1, PE = 2, FAIL = 3 };
// Целое число записано полностью (без знака '+', без лишних символов) и помещается в long long.
bool parse_int(const std::string& text, long long& value) {
const char* end = text.data() + text.size();
const auto result = std::from_chars(text.data(), end, value);
return result.ec == std::errc() && result.ptr == end;
}
// Сравнивает ответ участника с ответом жюри и печатает вердикт.
Verdict check(std::istream& input, std::istream& output, std::istream& answer) {
std::string a_text, b_text, jury_text, contestant_text, extra;
long long a = 0, b = 0, jury = 0, contestant = 0;
if (!(input >> a_text >> b_text) || !parse_int(a_text, a) || !parse_int(b_text, b)) {
std::cout << "FAIL: input does not contain two integers\n";
return FAIL;
}
if (!(answer >> jury_text) || !parse_int(jury_text, jury) || jury != a + b) {
std::cout << "FAIL: jury answer is wrong or missing\n";
return FAIL;
}
if (!(output >> contestant_text) || !parse_int(contestant_text, contestant)) {
std::cout << "WA: no integer in the contestant output\n";
return WA;
}
if (contestant != jury) {
std::cout << "WA: expected " << jury << ", got " << contestant << "\n";
return WA;
}
if (output >> extra) {
std::cout << "PE: extra text after the answer: " << extra << "\n";
return PE;
}
std::cout << "OK\n";
return OK;
}
// Если аргументов не три, программа показывает встроенные примеры: по одному на каждый код возврата.
int demo() {
struct Test { const char* input; const char* output; const char* answer; };
const Test tests[] = {
{"2 3\n", "5\n", "5\n"},
{"2 3\n", "6\n", "5\n"},
{"2 3\n", "5 7\n", "5\n"},
{"2 3\n", "4\n", "4\n"},
};
for (const Test& test : tests) {
std::istringstream input(test.input), output(test.output), answer(test.answer);
const Verdict verdict = check(input, output, answer);
std::cout << "exit code " << verdict << "\n";
}
return 0;
}
// Запуск: check input.txt output.txt answer.txt; код возврата - вердикт.
int main(int argc, char* argv[]) {
if (argc != 4) return demo();
std::ifstream input(argv[1]), output(argv[2]), answer(argv[3]);
return check(input, output, answer);
}
Чекер на Delphi
Обычно файл сheck.dpr, может быть check.pas (на Borland Pascal).
Для компиляции нужна библиотека testlib.pas, которую, как правило, можно найти там же в архиве.
Для компиляции можно: положить testlib.pas в ту же папку, что и check.dpr и выполнить команду dcc32 check.dpr.
Пример чекера check.dpr (русские буквы должны быть в DOS-кодировке cp866):
{$APPTYPE CONSOLE}
Uses TestLib, SysUtils;
{ Чекер для задачи A+B (вывести сумму чисел, без длинной арифметики) }
var A,B,C,J : int64;
begin
A := inf.readLongint; { Число A из входного файла }
B := inf.readLongint; { Число B из входного файла }
C := ouf.readLongint; { C (Contestant) - ответ участника }
J := ans.readLongint; { J (Jury) - ответ жюри, может не использоваться! }
if C <> J then { Wrong Answer }
Quit(_WA,Format('%d + %d = %d, а выведено %d',[A,B,A+B,C]));
Quit(_OK,''); { Тест пройден! }
end.
Чекер на С/C++
Обычно файл называется check.cpp. Для компиляции чаще всего нужна библиотека testlib.h (Mike Mirzayanov), с сайта http://code.google.com/p/testlib/.
Для компиляции можно использовать строку вида:
g++ -x c++ -O2 -Wall -Wl,--stack=67108864 check.cpp -o check.exe
Пример чекера check.cpp:
#include "testlib.h"
int main( int argc, char *argv[] ) {
setName("Чекер для задачи A+B");
registerTestlibCmd(argc, argv); // Обработка параметров командной строки
int a = inf.readInt(), b = inf.readInt(); // Чтение исходных данных
int pa = ouf.readInt(); // Ответ участника
int ja = ans.readInt(); // Ответ жюри
if (ja != pa) // Wrong Answer
quitf(_wa, "%d + %d = %d, а выведено %d", a, b, ja, pa );
quitf(_ok, "ans = %d, a=%d,b=%d", pa, a, b); // Тест пройден
}
2. Прогон на всех тестах с контролем времени и памяти
Для этого можно использовать программу run.exe, которую удобно поместить в папку с решением и тестами. По-умолчанию программа ищет решение solution.dpr, компилирует его Delphi (dcc32), и запускает на всех тестах (01, 02,... до 99) используя имя входного файла input.txt, а выходного output.txt. Для изменения этих настроек можно запустить программу run c параметрами командной строки или создать файл task.cfg. Пример файла task.cfg:
InputFile := bubble.in; OutputFile := bubble.out; CheckResult := true;
- InputFile - имя входного файла.
- OutputFile - имя выходного файла.
- CheckResult - запускать ли чекер check.exe.
3. Сборка условий задач (если они формате TeX)
Под Windows можно использовать MikTex - http://miktex.org. В разделе Download выберите подходящую версию. После установки удобно указать автоматическую доустановку пакетов.
Для сборки можно использовать bat/cmd файл следующего вида:
@echo off set CURRENT=ИМЯ_TEX_ФАЙЛА latex %CURRENT% dvips -t landscape %CURRENT% dvipdfm -p a4 -l %CURRENT%