一般在做题时,会被一些数据卡住,除了边界数据外,很多数据是随机生成的,为了适配普遍情况的随机数据。

但是在线评测系统(OJ)一般不公开测试数据,这是一个OJ 的命脉。

做题的时候,时常会很难造出来一些数据,这时候,就可以随机生成数据,再用一个已知正确的做法去对比答案(如果有std,则可以采用std,否则可以自己写一个暴力的做法,暴力虽然不能通过题目,但是可以帮助我们debug)。

下面是一个对拍程序的几个部分:

  • 数据生成器:gen
  • 需要debug的代码 my.cpp
  • 已知正确的代码 std.cpp
  • 运行程序并对比答案的脚本 check.sh

题目

求解 $A \times B$ ,其中 A 和 B 都是 $32$ 位有符号整数。

my.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <iostream>

int main()
{
    int a, b;
    std::cin >> a >> b;
    std::cout << a * b << std::endl;
    
    return 0;
}

std.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <iostream>

int main()
{
    long long a, b;
    std::cin >> a >> b;
    std::cout << a * b << std::endl;
    
    return 0;
}

gen

1
2
3
4
5
6
#!/usr/bin/python3

import random
a = random.randint(-2**31, 2**31-1)
b = random.randint(-2**31, 2**31-1)
print(a, b)

check.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

g++ -std=c++11 std.cpp -o std
g++ -std=c++11 my.cpp -o my

for((i=1;i<=100;i++))
do
  ./gen > gen.in
  ./std < gen.in > std.out   # 计算正确答案
  ./my < gen.in > my.out     # 计算待测试算法的输出结果

  if diff -w std.out my.out > /dev/null; then
    echo "Test $i: AC"
  else
    echo "Test $i: WA"
    exit 0
  fi
done

echo "All tests passed"

写好后,运行 check.sh

运行多次,结果如下:

可以发现几乎都是在 Test1 就发现了错误的数据,这得益于这道题的数据很好溢出。

一般来说,如果一次执行不成功,可以尝试多次,如果多次都不成功,可能问题不在于普通数据上,需要考虑边界数据了。

发现错误后

发现了 WA 后,去当前路径下的 gen.in 中得到数据,并进行 debug 。一般来说,数据不要太大,否则不好 debug 。