Если вы написали несколько задач и подготовили для них тесты, вероятно, вы будете крайне неприятно себя чувствовать, если какие-то из тестов окажутся некорректными (в том смысле, что они не будут согласованы с условием задачи): значение какой-то величины будет больше допустимой верхней границы для нее, граф не будет удовлетворять требованиям связности или же не будет являться деревом...↵
Это естественно, что вы будете себя так чувствовать. Даже опытные авторы задач не застрахованы от ошибок (это случается даже на самых престижных соревнованиях: пример тому — финал чемпионата мира ACM ICPC 2007 г.)↵
↵
Настоятельно рекомендуется писать специальную программу (называемую валидатором), чтобы формально проверить каждый тест на соответствие всем требованиям условия задачи.↵
Валидаторы обязательны для задач, которые готовятся для Codeforces. [Polygon](https://polygon.codeforces.com) имеет встроенную поддержку валидаторов.↵
↵
Написать валидатор с помощью testlib.h на самом деле очень легко. ↵
↵
## Пример↵
↵
Ниже приводится валидатор, который была написан для задачи [problem:100541A]:↵
↵
~~~~~↵
#include "testlib.h"↵
↵
int main() {↵
registerValidation();↵
int testCount = inf.readInt(1, 10, "testCount");↵
inf.readEoln();↵
↵
for (int i = 0; i < testCount; i++) {↵
int n = inf.readInt(1, 100, "n");↵
inf.readChar(' 'Space();↵
inf.readInt(1, 1000000, "w");↵
inf.readEoln();↵
↵
for(int i = 0; i < n; ++i) {↵
inf.readInt(1, 1000, "p_i");↵
if (i < n-1)↵
inf.readChar(' 'Space();↵
}↵
inf.readEoln();↵
}↵
↵
inf.readEof();↵
}↵
~~~~~↵
↵
Самое замечательное в этом валидаторе то, что он очень простой, и в нем очень трудно написать что-то неправильно.↵
↵
В репозитории Github можно найти другие [примеры валидаторов](https://github.com/MikeMirzayanov/testlib/tree/master/validators).↵
↵
## Функции и методы↵
↵
Первая строка вашего кода должна содержать вызов `registerValidation()`: немного магии, и вы можете использовать необходимые методы. ↵
↵
[cut]↵
↵
Большинство методов для валидатора начинаются с префикса _read_ и именно выполняют чтение: перемещают указатель во входном потоке на следующую позицию после прочтения чего-либо. В процессе чтения обнаруживаются нарушения (входные данные не соответствуют тому, что вы пытаетесь прочитать: например, вы предпринимаете попытку прочитать целое число, а во входных данных встречается строка) и выбрасывается ошибка.↵
↵
**Замечания**:↵
↵
- Валидатор строг. Он проверяет корректное расположение пробелов. Например, последовательность вызовов вида _прочесть число_, _прочесть пробел_, _прочесть число_ гарантирует наличие ровно одного пробела между числами; в противном случае валидатор сообщит об ошибке.↵
- Некоторые методы частично поддерживают синтаксис регулярных выражений. Конечно, это не полноценные регулярные выражения, которые вы можете использовать во многих языках программирования. Это очень простая версия, в которой поддерживается следующее:↵
- **Множество** символов: например, `[a-z]` — любые строчные латинские буквы, `[^a-z]` — любые символы за исключением строчных латинских букв.↵
- **Диапазон**, например, шаблон `[a-z]{1,5}` описывает строки длиной от 1 до 5 символов, содержащие только строчные латинские буквы.↵
- Оператор **Или**, например, шаблон `mike|john` — это или строка `mike`, или строка `john`.↵
- **Необязательные** символы, например, шаблон `-?[1-9][0-9]{0,3}` допускает ненулевые целые числа от -9999 до 9999 (обратите внимание на необязательный знак "минус").↵
- **Повторения**, например, шаблон `[0-9]*` допускает последовательности (как пустые, так и непустые) цифр, а шаблон `[0-9]+` только непустые последовательности цифр.↵
- Также заметим, что при распознавании регулярных выражений используется очень простой жадный алгоритм. Например, шаблон `[0-9]?1` не допускает `1` в силу жадного поведения распознавателя.↵
↵
Ниже представлен полный список функций и методов↵
↵
|Метод / функция|Что делает|↵
|-|-|↵
|void registerValidation()| Эта функция должна быть вызвана в начале вашего кода, чтобы использовать валидатор. После вызова этой функции вы получаете доступ к входному потоку посредством переменной `inf`. |↵
|char readChar()| Этот метод возвращает текущий символ и перемещает указатель на один символ вперед.|↵
|char readChar(char c)| Аналогичен `readChar()`, но обеспечивает проверку, что прочитанный символ именно `c`.|↵
|char readSpace()| Аналогичен `readChar(' ')`.|↵
|void unreadChar(char c)| Возвращает символ `c` во входной поток.|↵
|string readToken()|Читает и возвращает очередную лексему (токен).|↵
|string readToken(string regex)|Аналогичен `readToken()`, но выполняет проверку соответствия лексемы (токена) указанному регулярному выражению `regex`.|↵
|string readWord()|Аналогичен `readToken()`.|↵
|string readWord(string regex)|Аналогичен `readToken(string regex)`.|↵
|long long readLong()|Читает и возвращает длинное целое (`long long` в C/C++ и `long` в Java)|↵
|long long readLong(int L, int R)|Аналогичен `readLong()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|int readInt(), <br> int readInteger()|Читает и возвращает целое число (тип `int` как в Java, так и в C/C++)|↵
|int readInt(int L, int R), <br> int readInteger(L, R)|Аналогичны `readInt()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|double readReal(), <br> double readDouble()|Читают и возвращают вещественное число (`double`).|↵
|double readReal(double L, double R), <br> double readDouble(double L, double R)|Аналогичны `readReal()`, `readDouble()`, но выполняют проверку, что значение находится в диапазоне $[L, R]$.|↵
|double readStrictReal(double L, double R, int minPrecision, int maxPrecision), <br> double readStrictDouble(double L, double R, int minPrecision, int maxPrecision)|Аналогичны `readReal(L, R)`, `readDouble(L, R)`, но выполняют дополнительную проверку, что количество цифр после десятичной точки находится в диапазоне $[minPrecision, maxPrecision]$. Экспоненциальная запись числа или другие нестандартные формы записи не допускаются.|↵
|string readString(), <br> string readLine()|Прочитывают строку, начиная с текущей позиции до EOLN. Перемещают указатель во входном потоке на первый символ следующей строки (если она существует).|↵
|string readString(string regex), <br> string readLine(string regex)|Аналогичны `readString()` and `readLine()`, но выполняют проверку, что строка соответствует указанному регулярному выражению `regex`.|↵
|void readEoln()|Читает EOLN или завершает работу с ошибкой. Заметим, что этот метод чудесным образом работает как для Windows, так и для Linux. В Windows он прочитывает #13#10, а в Linux #10.|↵
|void readEof()|Читает EOF или завершает работу с ошибкой.|↵
↵
↵
#### Параметр _variableName_↵
↵
Рекомендуется использовать последний строковый параметр _variableName_ в методах readInt/readInteger/readLong/readDouble/readWord/readToken/readString/readLine, чтобы сделать сообщение об ошибке более удобным для чтения. Т.е. предпочтительнее использовать `inf.readInt(1, 100, n)` вместо `inf.readInt(1, 100)`. При возникновении ошибки в первом случае будет выводиться сообщение вида `FAIL Integer parameter [name=n] equals to 0, violates the range [1, 100]`.↵
↵
#### Использование _ensure/ensuref_↵
↵
Чтобы проверить некоторые требования (например, то, что граф не содержит петель, т.е. что $x_i \ne y_i$), используйте `ensuref(x_i != y_i, "Graph can't contain loops")`. Допускается использование спецификаторов формата языка C, подобных `ensuref(s.length() % 2 == 0, "String 's' should have even length, but s.length()=%d", int(s.length()))`.↵
Также вы можете использовать более простую форму `ensure(x > y)`, в этом случае будет печататься нарушенное условие, если оно не выполняется: `FAIL Condition failed: "x > y"`.↵
↵
Ссылки: [страница testlib.h на Github](https://github.com/MikeMirzayanov/testlib/blob/master/testlib.h)↵
Это естественно, что вы будете себя так чувствовать. Даже опытные авторы задач не застрахованы от ошибок (это случается даже на самых престижных соревнованиях: пример тому — финал чемпионата мира ACM ICPC 2007 г.)↵
↵
Настоятельно рекомендуется писать специальную программу (называемую валидатором), чтобы формально проверить каждый тест на соответствие всем требованиям условия задачи.↵
Валидаторы обязательны для задач, которые готовятся для Codeforces. [Polygon](https://polygon.codeforces.com) имеет встроенную поддержку валидаторов.↵
↵
Написать валидатор с помощью testlib.h на самом деле очень легко. ↵
↵
## Пример↵
↵
Ниже приводится валидатор, который была написан для задачи [problem:100541A]:↵
↵
~~~~~↵
#include "testlib.h"↵
↵
int main() {↵
registerValidation();↵
int testCount = inf.readInt(1, 10, "testCount");↵
inf.readEoln();↵
↵
for (int i = 0; i < testCount; i++) {↵
int n = inf.readInt(1, 100, "n");↵
inf.read
inf.readInt(1, 1000000, "w");↵
inf.readEoln();↵
↵
for(int i = 0; i < n; ++i) {↵
inf.readInt(1, 1000, "p_i");↵
if (i < n-1)↵
inf.read
}↵
inf.readEoln();↵
}↵
↵
inf.readEof();↵
}↵
~~~~~↵
↵
Самое замечательное в этом валидаторе то, что он очень простой, и в нем очень трудно написать что-то неправильно.↵
↵
В репозитории Github можно найти другие [примеры валидаторов](https://github.com/MikeMirzayanov/testlib/tree/master/validators).↵
↵
## Функции и методы↵
↵
Первая строка вашего кода должна содержать вызов `registerValidation()`: немного магии, и вы можете использовать необходимые методы. ↵
↵
[cut]↵
↵
Большинство методов для валидатора начинаются с префикса _read_ и именно выполняют чтение: перемещают указатель во входном потоке на следующую позицию после прочтения чего-либо. В процессе чтения обнаруживаются нарушения (входные данные не соответствуют тому, что вы пытаетесь прочитать: например, вы предпринимаете попытку прочитать целое число, а во входных данных встречается строка) и выбрасывается ошибка.↵
↵
**Замечания**:↵
↵
- Валидатор строг. Он проверяет корректное расположение пробелов. Например, последовательность вызовов вида _прочесть число_, _прочесть пробел_, _прочесть число_ гарантирует наличие ровно одного пробела между числами; в противном случае валидатор сообщит об ошибке.↵
- Некоторые методы частично поддерживают синтаксис регулярных выражений. Конечно, это не полноценные регулярные выражения, которые вы можете использовать во многих языках программирования. Это очень простая версия, в которой поддерживается следующее:↵
- **Множество** символов: например, `[a-z]` — любые строчные латинские буквы, `[^a-z]` — любые символы за исключением строчных латинских букв.↵
- **Диапазон**, например, шаблон `[a-z]{1,5}` описывает строки длиной от 1 до 5 символов, содержащие только строчные латинские буквы.↵
- Оператор **Или**, например, шаблон `mike|john` — это или строка `mike`, или строка `john`.↵
- **Необязательные** символы, например, шаблон `-?[1-9][0-9]{0,3}` допускает ненулевые целые числа от -9999 до 9999 (обратите внимание на необязательный знак "минус").↵
- **Повторения**, например, шаблон `[0-9]*` допускает последовательности (как пустые, так и непустые) цифр, а шаблон `[0-9]+` только непустые последовательности цифр.↵
- Также заметим, что при распознавании регулярных выражений используется очень простой жадный алгоритм. Например, шаблон `[0-9]?1` не допускает `1` в силу жадного поведения распознавателя.↵
↵
Ниже представлен полный список функций и методов↵
↵
|Метод / функция|Что делает|↵
|-|-|↵
|void registerValidation()| Эта функция должна быть вызвана в начале вашего кода, чтобы использовать валидатор. После вызова этой функции вы получаете доступ к входному потоку посредством переменной `inf`. |↵
|char readChar()| Этот метод возвращает текущий символ и перемещает указатель на один символ вперед.|↵
|char readChar(char c)| Аналогичен `readChar()`, но обеспечивает проверку, что прочитанный символ именно `c`.|↵
|char readSpace()| Аналогичен `readChar(' ')`.|↵
|void unreadChar(char c)| Возвращает символ `c` во входной поток.|↵
|string readToken()|Читает и возвращает очередную лексему (токен).|↵
|string readToken(string regex)|Аналогичен `readToken()`, но выполняет проверку соответствия лексемы (токена) указанному регулярному выражению `regex`.|↵
|string readWord()|Аналогичен `readToken()`.|↵
|string readWord(string regex)|Аналогичен `readToken(string regex)`.|↵
|long long readLong()|Читает и возвращает длинное целое (`long long` в C/C++ и `long` в Java)|↵
|long long readLong(int L, int R)|Аналогичен `readLong()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|int readInt(), <br> int readInteger()|Читает и возвращает целое число (тип `int` как в Java, так и в C/C++)|↵
|int readInt(int L, int R), <br> int readInteger(L, R)|Аналогичны `readInt()`, но выполняет проверку, что значение находится в диапазоне $[L, R]$ (включительно)|↵
|double readReal(), <br> double readDouble()|Читают и возвращают вещественное число (`double`).|↵
|double readReal(double L, double R), <br> double readDouble(double L, double R)|Аналогичны `readReal()`, `readDouble()`, но выполняют проверку, что значение находится в диапазоне $[L, R]$.|↵
|double readStrictReal(double L, double R, int minPrecision, int maxPrecision), <br> double readStrictDouble(double L, double R, int minPrecision, int maxPrecision)|Аналогичны `readReal(L, R)`, `readDouble(L, R)`, но выполняют дополнительную проверку, что количество цифр после десятичной точки находится в диапазоне $[minPrecision, maxPrecision]$. Экспоненциальная запись числа или другие нестандартные формы записи не допускаются.|↵
|string readString(), <br> string readLine()|Прочитывают строку, начиная с текущей позиции до EOLN. Перемещают указатель во входном потоке на первый символ следующей строки (если она существует).|↵
|string readString(string regex), <br> string readLine(string regex)|Аналогичны `readString()` and `readLine()`, но выполняют проверку, что строка соответствует указанному регулярному выражению `regex`.|↵
|void readEoln()|Читает EOLN или завершает работу с ошибкой. Заметим, что этот метод чудесным образом работает как для Windows, так и для Linux. В Windows он прочитывает #13#10, а в Linux #10.|↵
|void readEof()|Читает EOF или завершает работу с ошибкой.|↵
↵
↵
#### Параметр _variableName_↵
↵
Рекомендуется использовать последний строковый параметр _variableName_ в методах readInt/readInteger/readLong/readDouble/readWord/readToken/readString/readLine, чтобы сделать сообщение об ошибке более удобным для чтения. Т.е. предпочтительнее использовать `inf.readInt(1, 100, n)` вместо `inf.readInt(1, 100)`. При возникновении ошибки в первом случае будет выводиться сообщение вида `FAIL Integer parameter [name=n] equals to 0, violates the range [1, 100]`.↵
↵
#### Использование _ensure/ensuref_↵
↵
Чтобы проверить некоторые требования (например, то, что граф не содержит петель, т.е. что $x_i \ne y_i$), используйте `ensuref(x_i != y_i, "Graph can't contain loops")`. Допускается использование спецификаторов формата языка C, подобных `ensuref(s.length() % 2 == 0, "String 's' should have even length, but s.length()=%d", int(s.length()))`.↵
Также вы можете использовать более простую форму `ensure(x > y)`, в этом случае будет печататься нарушенное условие, если оно не выполняется: `FAIL Condition failed: "x > y"`.↵
↵
Ссылки: [страница testlib.h на Github](https://github.com/MikeMirzayanov/testlib/blob/master/testlib.h)↵