# BitOJ 自定义验证程序完整指南 ## 概述 BitOJ系统支持4种判题方式: 1. **字符串精确比较** - 逐字符对比输出 2. **字符串容错比较** - 允许格式错误(PE),主要比较数字内容 3. **文件MD5校验** - 比较文件大小和MD5值 4. **自定义验证程序** - 编写专门的验证逻辑 本文档重点介绍第4种方式:自定义验证程序的编写和使用。 ## 自定义验证程序原理 ### 工作流程 1. 系统执行用户提交的代码 2. 将输入、期望输出、实际输出传递给验证程序 3. 验证程序分析这些文件并返回判题结果 4. 系统根据返回结果确定最终评分 ### 参数说明 验证程序接收以下参数: - `argv[1]`: 标准输入文件路径 - `argv[2]`: 期望输出文件路径 - `argv[3]`: 用户程序输出文件路径 ### 返回值 验证程序必须输出以下结果之一: - `AC` - Accepted(答案正确) - `PE` - Presentation Error(格式错误) - `WA` - Wrong Answer(答案错误) ## 实际示例 ### 1. 浮点数误差比较 (C++) **适用场景**: 计算几何、数值计算等需要浮点数比较的题目 ```cpp #include #include #include using namespace std; const double EPS = 1e-9; int main(int argc, char* argv[]) { ifstream expected(argv[2]); // 标准答案 ifstream result(argv[3]); // 用户输出 double exp_val, res_val; if (!(expected >> exp_val) || !(result >> res_val)) { cout << "WA" << endl; return 0; } if (fabs(exp_val - res_val) <= EPS) { cout << "AC" << endl; } else { cout << "WA" << endl; } return 0; } ``` ### 2. 多解答案验证 (Python) **适用场景**: 排序题、图论路径题等有多种正确答案的题目 ```python #!/usr/bin/env python import sys def main(): try: with open(sys.argv[2], 'r') as f: expected = f.read().strip() with open(sys.argv[3], 'r') as f: result = f.read().strip() # 解析数字并排序比较 expected_nums = sorted(map(int, expected.split())) result_nums = sorted(map(int, result.split())) if expected_nums == result_nums: print("AC") else: print("WA") except: print("WA") if __name__ == "__main__": main() ``` ### 3. 输出格式验证 (Java) **适用场景**: 需要严格输出格式的竞赛题目 ```java import java.io.*; import java.util.*; import java.util.regex.Pattern; public class StringFormatValidator { public static void main(String[] args) { try { Scanner result = new Scanner(new File(args[2])); int lineNum = 1; while (result.hasNextLine()) { String line = result.nextLine().trim(); // 检查格式:Case #X: Y Pattern pattern = Pattern.compile("^Case #" + lineNum + ": \\d+$"); if (!pattern.matcher(line).matches()) { System.out.println("PE"); return; } lineNum++; } System.out.println("AC"); } catch (Exception e) { System.out.println("WA"); } } } ``` ## 在BitOJ中配置自定义验证程序 ### 代码配置示例 ```python from judgescript import ExternalJudge # 创建自定义验证程序 validator = ExternalJudge( problemid='P1001', # 题目ID vlang='gcc-3.3', # 验证程序语言 vcode=validator_code # 验证程序源代码 ) # 在测试过程中调用 result = validator.judge( sid='S123', # 提交ID tid='T001', # 测试用例ID tin='/path/to/input.txt', # 输入文件 tout='/path/to/output.txt', # 期望输出 result='/path/to/result.txt', # 实际输出 errfile='/path/to/error.txt' # 错误输出 ) ``` ### 支持的编程语言 | 语言 | 标识符 | 说明 | |------|--------|------| | C | gcc-3.3 | 适合高性能验证 | | C++ | g++-3.3 | 支持STL容器 | | Java | java-1.6 | 强类型安全 | | Python | python-2.5 | 快速开发 | | Pascal | fpc-2.2 | 简单逻辑 | ## 最佳实践 ### 1. 错误处理 ```cpp // 文件读取失败处理 if (!input_file.is_open()) { cout << "WA" << endl; return 0; } // 数据解析失败处理 try { value = stod(line); } catch (const exception& e) { cout << "WA" << endl; return 0; } ``` ### 2. 性能优化 - 使用适当的数据结构 - 避免不必要的字符串操作 - 合理设置缓冲区大小 - 注意内存使用限制 ### 3. 安全考虑 - 验证输入参数数量 - 处理异常文件路径 - 限制递归深度 - 避免无限循环 ### 4. 可维护性 - 添加清晰的注释 - 使用有意义的变量名 - 模块化验证逻辑 - 提供调试输出选项 ## 常见应用场景 ### 1. 数值计算题 - 浮点数精度比较 - 矩阵运算结果验证 - 统计数值的近似比较 ### 2. 图论算法题 - 最短路径验证(允许多条等长路径) - 最小生成树验证(权重相等即可) - 图遍历结果验证 ### 3. 字符串处理题 - 忽略大小写比较 - 忽略空白字符差异 - 正则表达式匹配 ### 4. 组合数学题 - 排列组合结果验证 - 集合操作结果比较 - 数学证明步骤检查 ### 5. 交互式题目 - 模拟交互过程 - 验证查询次数限制 - 检查答案正确性 ## 调试技巧 ### 1. 本地测试 ```bash # 编译验证程序 g++ -o validator validator.cpp # 准备测试文件 echo "3.14159" > expected.txt echo "3.14160" > result.txt # 运行测试 ./validator input.txt expected.txt result.txt ``` ### 2. 日志输出 ```cpp #ifdef DEBUG cerr << "Expected: " << exp_val << ", Got: " << res_val << endl; cerr << "Difference: " << fabs(exp_val - res_val) << endl; #endif ``` ### 3. 边界情况测试 - 空输出文件 - 超大数值 - 特殊字符 - 格式错误的输入 ## 故障排除 ### 常见问题 1. **编译失败** - 检查语言版本兼容性 - 确认头文件引用正确 - 验证语法错误 2. **运行超时** - 优化算法复杂度 - 减少不必要的计算 - 检查是否有死循环 3. **内存不足** - 减少内存分配 - 及时释放资源 - 使用流式处理 4. **判题结果异常** - 验证输出格式 - 检查返回值规范 - 确认异常处理逻辑 ## 总结 自定义验证程序是BitOJ系统最灵活的判题方式,能够处理各种复杂的判题需求。通过合理设计验证逻辑,可以支持: - 多解答案题目 - 浮点数精度要求 - 特殊输出格式 - 交互式评测 - 复杂的正确性检查 掌握自定义验证程序的编写技巧,能够大大扩展在线评测系统的应用范围,为各种类型的编程竞赛和教学需求提供支持。