Java算法竞赛对拍笔记
一、对拍概述
对拍是一种检测代码错误的方法,主要通过对比两个程序的输出结果来实现。
包含以下几个关键部分:
- 暴力程序:正确但低效的算法,通常采用完全搜索等方式。
- 待测程序:优化后的算法,需要验证其正确性。
- 数据生成器:随机生成符合要求的测试数据。
- 对拍脚本:自动运行并比较两个程序的输出结果。
二、对拍步骤与组件
1. 数据生成器(Maker)
作用:生成符合输入格式的随机测试数据。
示例代码(Java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import java.io.*; import java.util.Random;
public class Maker { public static void main(String[] args) { try (PrintWriter out = new PrintWriter("input.txt")) { Random rnd = new Random(); int n = rnd.nextInt(10) + 1; int m = rnd.nextInt(100); out.println(n + " " + m); for (int i = 0; i < n; i++) { out.println(rnd.nextInt(100) + " " + rnd.nextInt(100)); } } } }
|
2. 暴力程序(Brute Force)
作用:使用简单但正确的算法生成答案。
示例代码(Java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.io.*; import java.util.*;
public class Brute { public static void main(String[] args) throws IOException { Scanner in = new Scanner(new File("input.txt")); PrintWriter out = new PrintWriter("brute.out"); int n = in.nextInt(); int m = in.nextInt(); int[] w = new int[n]; int[] c = new int[n]; for (int i = 0; i < n; i++) { w[i] = in.nextInt(); c[i] = in.nextInt(); } int max = 0; for (int mask = 0; mask < (1 << n); mask++) { int weight = 0, cost = 0; for (int i = 0; i < n; i++) { if ((mask & (1 << i)) != 0) { weight += w[i]; cost += c[i]; } } if (weight <= m && cost > max) { max = cost; } } out.println(max); out.close(); } }
|
3. 待测程序(Solution)
作用:实现优化算法,需与暴力程序结果一致。
示例代码(Java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import java.io.*; import java.util.*;
public class Solution { public static void main(String[] args) throws IOException { Scanner in = new Scanner(new File("input.txt")); PrintWriter out = new PrintWriter("solution.out"); int n = in.nextInt(); int m = in.nextInt(); int[] w = new int[n]; int[] c = new int[n]; for (int i = 0; i < n; i++) { w[i] = in.nextInt(); c[i] = in.nextInt(); } int[] dp = new int[m + 1]; for (int i = 0; i < n; i++) { for (int j = m; j >= w[i]; j--) { dp[j] = Math.max(dp[j], dp[j - w[i]] + c[i]); } } out.println(dp[m]); out.close(); } }
|
4. 对拍脚本
作用:自动运行生成器、暴力程序、待测程序,并比较输出结果。
Windows批处理脚本示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @echo off :loop echo 正在生成数据... javac Maker.java java Maker > input.txt echo 正在运行暴力程序... javac Brute.java java Brute < input.txt > brute.out echo 正在运行待测程序... javac Solution.java java Solution < input.txt > solution.out echo 正在比较结果... fc brute.out solution.out if errorlevel 1 ( echo 出错!请检查代码! pause exit ) echo 测试通过,继续下一轮... goto loop
|
Linux Bash脚本示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #!/bin/bash while true; do javac Maker.java && java Maker > input.txt javac Brute.java && java Brute < input.txt > brute.out javac Solution.java && java Solution < input.txt > solution.out diff brute.out solution.out if [ $? -ne 0 ]; then echo "Error! 请检查代码!" exit 1 else echo "AC! 继续测试..." fi done
|
三、注意事项
- 输入输出一致性:
- 确保所有程序的输入输出格式一致(如空格、换行符)。
- 使用
System.in
和 System.out
以便重定向,或手动读写文件。
- 数据覆盖:
- 数据生成器需覆盖边界条件(如最大值、最小值、极端情况)。
- 程序效率:
- 错误处理:
- 检查程序是否崩溃或输出异常(如
NullPointerException
)。
- 环境配置:
- 确保 Java 环境变量正确,路径无误。
- 在 Linux 下给脚本执行权限:
chmod +x script.sh
。
四、调试技巧
- 手动测试:
- 手动生成小规模数据(如
n=3
)。
- 手动运行程序并对比输出。
- 逐步调试:
- 在程序中添加
System.out.println
输出中间变量,检查逻辑错误。
五、总结
对拍是调试算法竞赛代码的有效工具,通过自动化测试能快速定位错误。熟练掌握对拍流程,可显著减少因细节错误导致的扣分。