Files
bitoj_python/examples/README_自定义验证程序.md

295 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <iostream>
#include <fstream>
#include <cmath>
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系统最灵活的判题方式能够处理各种复杂的判题需求。通过合理设计验证逻辑可以支持
- 多解答案题目
- 浮点数精度要求
- 特殊输出格式
- 交互式评测
- 复杂的正确性检查
掌握自定义验证程序的编写技巧,能够大大扩展在线评测系统的应用范围,为各种类型的编程竞赛和教学需求提供支持。