# BitOJ 自定义验证程序示例 ## 1. 基本验证程序结构 自定义验证程序接收以下参数: - 标准输入文件 - 标准输出文件(期望答案) - 用户输出文件(用户程序的输出) 验证程序需要输出以下结果之一: - `AC` - 答案正确 - `PE` - 格式错误(如果支持) - `WA` - 答案错误 ## 2. 示例1:数值误差比较验证程序(C++) 适用于需要浮点数比较的题目: ```cpp #include #include #include #include using namespace std; const double EPS = 1e-9; int main(int argc, char* argv[]) { // argv[1]: 标准输入文件 // argv[2]: 标准输出文件 // argv[3]: 用户输出文件 ifstream expected(argv[2]); // 标准答案 ifstream result(argv[3]); // 用户输出 double exp_val, res_val; // 读取期望的浮点数 if (!(expected >> exp_val)) { cout << "WA" << endl; return 0; } // 读取用户输出的浮点数 if (!(result >> res_val)) { cout << "WA" << endl; return 0; } // 比较数值,允许误差 if (fabs(exp_val - res_val) <= EPS) { cout << "AC" << endl; } else { cout << "WA" << endl; } return 0; } ``` ## 3. 示例2:多解答案验证程序(Python) 适用于有多个正确答案的题目: ```python #!/usr/bin/env python import sys def main(): # sys.argv[1]: 标准输入文件 # sys.argv[2]: 标准输出文件 # sys.argv[3]: 用户输出文件 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 = list(map(int, expected.split())) result_nums = list(map(int, result.split())) # 检查数量是否相同 if len(expected_nums) != len(result_nums): print("WA") return # 检查排序后是否相同(原始数据相同) if sorted(expected_nums) != sorted(result_nums): print("WA") return # 检查用户输出是否有序 if result_nums == sorted(result_nums): print("AC") else: print("WA") except Exception as e: print("WA") if __name__ == "__main__": main() ``` ## 4. 示例3:图论路径验证程序(C++) 验证最短路径问题,检查路径是否合法且最优: ```cpp #include #include #include #include #include using namespace std; struct Edge { int to, weight; }; int main(int argc, char* argv[]) { ifstream input(argv[1]); // 输入数据 ifstream expected(argv[2]); // 期望答案 ifstream result(argv[3]); // 用户答案 // 读取图的信息 int n, m; input >> n >> m; vector> graph(n + 1); for (int i = 0; i < m; i++) { int u, v, w; input >> u >> v >> w; graph[u].push_back({v, w}); graph[v].push_back({u, w}); // 无向图 } int start, end; input >> start >> end; // 读取期望的最短距离 int expected_dist; expected >> expected_dist; // 读取用户输出的路径 string line; getline(result, line); istringstream iss(line); vector path; int node; while (iss >> node) { path.push_back(node); } // 验证路径 if (path.empty() || path[0] != start || path.back() != end) { cout << "WA" << endl; return 0; } // 计算路径长度 int total_dist = 0; for (int i = 0; i < path.size() - 1; i++) { int u = path[i], v = path[i + 1]; bool found = false; for (const Edge& e : graph[u]) { if (e.to == v) { total_dist += e.weight; found = true; break; } } if (!found) { cout << "WA" << endl; // 路径不存在 return 0; } } // 检查是否是最短路径 if (total_dist == expected_dist) { cout << "AC" << endl; } else { cout << "WA" << endl; } return 0; } ``` ## 5. 示例4:字符串格式验证程序(Java) 验证输出格式是否正确: ```java import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { // args[0]: 标准输入文件 // args[1]: 标准输出文件 // args[2]: 用户输出文件 Scanner expected = new Scanner(new File(args[1])); Scanner result = new Scanner(new File(args[2])); try { // 读取期望的行数 int expectedLines = expected.nextInt(); // 检查用户输出的行数 int actualLines = 0; List userLines = new ArrayList<>(); while (result.hasNextLine()) { String line = result.nextLine().trim(); if (!line.isEmpty()) { userLines.add(line); actualLines++; } } if (actualLines != expectedLines) { System.out.println("WA"); return; } // 检查每行格式:必须是 "Case #X: Y" 的格式 for (int i = 0; i < userLines.size(); i++) { String line = userLines.get(i); String pattern = "Case #" + (i + 1) + ": \\d+"; if (!line.matches(pattern)) { System.out.println("PE"); // 格式错误 return; } } System.out.println("AC"); } catch (Exception e) { System.out.println("WA"); } finally { expected.close(); result.close(); } } } ``` ## 6. 示例5:交互式题目验证程序(C++) 模拟交互过程: ```cpp #include #include #include #include using namespace std; int main(int argc, char* argv[]) { ifstream input(argv[1]); // 输入数据 ifstream expected(argv[2]); // 期望的查询次数等 ifstream result(argv[3]); // 用户的查询序列 // 读取隐藏的数字 int secret; input >> secret; // 读取最大查询次数 int maxQueries; expected >> maxQueries; // 模拟交互过程 int queryCount = 0; int guess; bool found = false; while (result >> guess && queryCount < maxQueries) { queryCount++; if (guess == secret) { found = true; break; } // 在实际交互中,这里会给用户反馈 "too high" 或 "too low" } // 检查结果 if (found && queryCount <= maxQueries) { cout << "AC" << endl; } else { cout << "WA" << endl; } return 0; } ``` ## 使用方法 1. **编写验证程序**:选择合适的编程语言编写验证逻辑 2. **设置题目**:在题目配置中指定使用自定义验证程序 3. **上传验证代码**:将验证程序代码保存到系统中 4. **测试验证**:确保验证程序能正确处理各种情况 ## 注意事项 1. **异常处理**:验证程序必须处理所有可能的异常情况 2. **性能考虑**:验证程序也有时间限制,需要高效实现 3. **输出格式**:验证程序必须严格按照 AC/PE/WA 格式输出 4. **安全性**:验证程序在沙箱环境中运行,有资源限制 5. **可移植性**:确保验证程序在评测环境中能正常编译运行 ## 配置示例 在 BitOJ 中配置自定义验证程序: ```python # 在题目配置中设置自定义验证程序 problem.validator_language = 'gcc-3.3' # 验证程序语言 problem.validator_code = ''' // 这里放置验证程序的源代码 ''' ```