对拍
简介
对拍是一种对学竞赛的同学非常有用的debug技能。在做题时,你肯定会遇到这样的情况:
???我不是过了样例吗???为什么WA了2个点???代码好像没什么问题啊???
辣鸡评测姬
这个时候你就需要对拍来调试程序了。
对拍,说白了就是拿一个输入数据分别让你写的程序和标程(暴力程序)跑一遍,比较输出的数据。
对拍一般有以下3个步骤:
- 生成一组输入数据
- 把这组数据分别让两个程序运行一遍,生成输出数据
- 比较两组输出数据
那么为了实现对拍,我们需要:
- 你的程序
- 标程
- 数据生成器
- 对拍脚本(批处理脚本)
如果你懒得看下面的内容可以直接在GitHub下载程序。 本文仅适用于Windows系统。
批处理脚本
假设你已经写好了一个数据生成器并编译成了rand.exe,那么我们可以把它的输出重定向到文件std.in:
1
rand.exe > std.in
输入重定向也类似,假设my.exe是你的程序,std.exe是标程:
1
2my.exe < std.in
std.exe < std.in1
2my.exe < std.in > my.out
std.exe < std.in > std.out
接下来就是比较了,Windows自带一个fc命令,用于比较两个文件:
1
fc my.out std.out /n
/n参数会显示行号。
这样我们就可以写出一个对拍脚本了: 1
2
3
4
5
6
7
8
9@echo off
:loop
rand.exe > std.in
my.exe < std.in > my.out
std.exe < std.in > std.out
fc my.out std.out /n
if not errorlevel 1 goto loop
pause
goto loop@echo off的作用是关闭输入显示;
:loop的作用与C中的goto类似,标号loop;
errorlevel是上一个命令的返回值,fc在文件相同时会返回0,不同时返回1。因此if not errorlevel 1 goto loop的意思是:如果fc返回的不是1,就跳转到loop(相当于循环);
一旦返回值为1,脚本就会以pause命令暂停,让你可以看数据;
最后goto loop,继续循环。
将这个脚本命名为check.bat,可以直接运行。
新鲜的炒栗
比如P1001 A+B Problem这道难题,我们先写出标程:
1
2
3
4
5
6
7
8
int main() {
int a, b;
std::cin >> a >> b;
std::cout << a + b << std::endl;
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {
int a, b, sum = 0, carry = 0;
std::cin >> a >> b;
do {
sum = a ^ b;
carry = (a & b) << 1;
a = sum;
b = carry;
}
while (carry);
std::cout << sum << std::endl;
return 0;
}
数据生成器怎么写呢?
头文件<cstdlib>中有一个rand()函数,可以生成0到RAND_MAX之间的一个随机整数。RAND_MAX也定义在<cstdlib>中,其值为2147483647。
由于题目要求有负数,因此可以再生成一个随机数来设置符号: 1
2
3
4
5
6
7
8
9
10
int main() {
const int p = 1000000000;
int a = std::rand() % p, b = std::rand() % p;
a = (std::rand() % 2 == 0 ? -a : a), b = (std::rand() % 2 == 0 ? -b : b);
std::cout << a << " " << b << std::endl;
return 0;
}srand()函数设置种子。
一般使用time(NULL)的返回值作为种子(对于C++
11,建议使用time(nullptr)),time()函数包含在<ctime>头文件中:
1
2
3
4
5
6
7
8
9
10
11
12
int main() {
const int p = 1000000000;
std::srand(std::time(nullptr));
int a = std::rand() % p, b = std::rand() % p;
a = (std::rand() % 2 == 0 ? -a : a), b = (std::rand() % 2 == 0 ? -b : b);
std::cout << a << " " << b << std::endl;
return 0;
}