Hướng dẫn sử dụng Generators trong FPT-OJ
Khi có một lượng lớn dữ liệu kiểm tra, thay vì tạo từng tệp đầu vào và đầu ra, ta có thể sử dụng generator – một chương trình tạo dữ liệu tự động dựa trên tham số dòng lệnh.
1. Generator Node
Node generator
có thể chứa:
- Một chuỗi đơn: Tên của tệp chương trình tạo dữ liệu.
- Một mảng: Phần tử đầu tiên là tệp nguồn (C hoặc C++), các phần tử còn lại là tệp phụ (ví dụ: tệp tiêu đề
.h
). - Một YAML associative array, chứa các khóa sau:
source
: Chuỗi tên tệp generator hoặc một mảng gồm tệp nguồn và các tệp phụ.language
: Ngôn ngữ của generator (nếu không có, hệ thống tự suy đoán).flags
: Các cờ bổ sung khi biên dịch (mặc định là[]
).compiler_time_limit
: Giới hạn thời gian biên dịch (mặc định theoenv.compiler_time_limit
, khuyến nghị đặt 60 giây nếu dùngtestlib.h
).time_limit
: Giới hạn thời gian chạy generator (mặc định theoenv.time_limit
).memory_limit
: Giới hạn bộ nhớ của generator (mặc định theoenv.memory_limit
).
Có thể khai báo generator
trong từng test case để sử dụng nhiều generator cho một bài toán.
2. Generator Arguments
Node generator_args
chứa danh sách tham số truyền vào generator (ép kiểu thành str
). Có thể khai báo ở mức tổng thể hoặc trong từng test case.
Ví dụ cấu hình YAML
generator: gen.cpp
test_cases:
- {generator_args: [false, 123, "a b\nc"], points: 10}
- {points: 20}
- Test case 1: Generator nhận 4 tham số:
"_aux_file"
,"False"
,"123"
,"a b\nc"
. - Test case 2: Không có
generator_args
, generator chỉ nhận"_aux_file"
.
3. Cách generator xuất dữ liệu
Generator cần:
- Ghi dữ liệu đầu vào vào stdout.
- Ghi dữ liệu đầu ra vào stderr.
Nếu một test case đã có tệp đầu vào (in
) và đầu ra (out
), generator sẽ không chạy cho test case đó.
4. Cách FPTOJ so sánh kết quả
FPTOJ sử dụng generator để sinh dữ liệu đầu vào và đầu ra đúng, sau đó so sánh với đầu ra của thí sinh:
- Thí sinh đọc dữ liệu từ stdin, sau đó thực hiện xử lý bài toán và in kết quả ra stdout.
- Generator sinh đầu vào ra stdout, và tính toán kết quả đúng ra stderr.
- FPTOJ chạy chương trình của thí sinh với đầu vào sinh bởi generator, rồi so sánh stdout của thí sinh với stderr của generator.
Nếu hai kết quả khớp nhau, bài làm được tính là đúng. Nếu khác nhau, thí sinh bị chấm sai.
Ví dụ:
- Generator sinh đầu vào
10 20\n
ra stdout. - Generator tính toán và in kết quả
30\n
ra stderr. - Thí sinh chạy chương trình, đọc
10 20
từ stdin và in kết quả30
ra stdout. - Hệ thống FPTOJ kiểm tra
stdout (thí sinh) == stderr (generator)
, nếu đúng thì test case pass.
Cách này giúp giảm bớt việc lưu trữ tệp đầu vào và đầu ra cố định, đồng thời hỗ trợ test case linh hoạt hơn.
5. Ví dụ mã nguồn generator
Ví dụ 1 bài : https://fptoj.com/problem/chiadoan
Ví dụ 1: Sinh dãy số ngẫu nhiên
#include <iostream>
#include <cstdlib>
#include <ctime>
int main(int argc, char* argv[]) {
std::srand(std::time(0));
int n = (argc > 1) ? std::atoi(argv[1]) : 10; // Số phần tử, mặc định là 10
std::cout << n << "\n"; // Ghi dữ liệu đầu vào vào stdout
for (int i = 0; i < n; i++) {
std::cout << (std::rand() % 100) << " ";
}
std::cout << "\n";
std::cerr << "OK" << std::endl; // Ghi dữ liệu đầu ra vào stderr
return 0;
}
Ví dụ 2: Sinh test case cho bài toán tìm ước chung lớn nhất (GCD)
#include <iostream>
#include <cstdlib>
#include <ctime>
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main(int argc, char* argv[]) {
std::srand(std::time(0));
int a = std::rand() % 1000 + 1;
int b = std::rand() % 1000 + 1;
std::cout << a << " " << b << "\n";
std::cerr << gcd(a, b) << "\n";
return 0;
}
Ví dụ 3: Sinh test case cho bài toán chuỗi đảo ngược
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
std::string random_string(int length) {
const std::string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string result = "";
for (int i = 0; i < length; i++) {
result += chars[std::rand() % chars.length()];
}
return result;
}
int main(int argc, char* argv[]) {
std::srand(std::time(0));
int length = (argc > 1) ? std::atoi(argv[1]) : 10;
std::string str = random_string(length);
std::cout << str << "\n";
std::cerr << std::string(str.rbegin(), str.rend()) << "\n";
return 0;
}
Với hướng dẫn này, các thầy cô có thể dễ dàng áp dụng generator vào hệ thống FPT-OJ để quản lý dữ liệu test hiệu quả hơn!