# 对拍是什么
对拍,是一个比较实用的工具。它能够非常方便地对于两个程序的输出文件进行比较,可以帮助我们实现一些自动化的比较输出结果的问题。
众所周知,几乎每一道编程题目,都会有某种正解能拿到满分;当我们想不出正解时,我们往往可以打暴力代码来获取部分分数。
但是,当我们觉得有思路写正解,但又担心自己正解写的不对,而恰好,我们又有一个能够暴力骗分的代码。这个时候就可以用到对拍。 暴力骗分代码必须保证正确性,只是超出时间限制,不能出现答案错误的情况。
这样,我们可以造多组数据,让暴力骗分的程序跑一遍,再让我们自己写的正解跑一遍,二者进行多次对比。如果多组数据都显示二者的输出结果一样,那么这个正解大概率没问题。相反地,如果两组数据不同,我们就找到了一组错误数据,方便调试,找到正解哪里出了问题。
这便是对拍。其作用也在上文提出。
# 对拍的实现
# 准备基本代码
首先,我们要有 2 份代码,一份是这一道题 “你写的正解” 代码,另一份是同一道题 “你打的暴力” 代码。
两份代码有了,将它们全部编译。我们把它们放在同一个文件夹里。这样算是做好了对拍的准备。
# 制作数据生成器
也就是
#include <bits/stdc++.h> | |
using namespace std; | |
typedef long long ll; | |
ll Random(ll mod) { | |
ll ans = 2147483647; | |
return ans = ans * rand() % mod + 1; // 1 到 mod 之间的数 | |
} | |
signed main() { | |
struct _timeb T; | |
_ftime(&T); | |
srand(T.millitm); | |
// 生成随机数种子,利用 timeb 生成毫秒级别随机数 | |
ll a, b; | |
a = Random(1e12), b = Random(1e12); | |
cout << a << ' ' << b; | |
// 这样就生成了 2 个随机数 | |
} |
rand () 只会生成 0~32767 的数据
# 对拍代码
# 标准输入输出代码
标准输入输出指的是:两份基本代码和数据生成代码里不含文件输入输出操作,如 freopen 等。
在这里,我们需要用到一些文件的读写符号。(需用到 <cstdlib> 库)
system ("data.exe> in.txt") 指的是运行 data.exe,把结果输出(>)到 in.txt 中。
system ("wa.exe < in.txt> wa.txt") 指的是运行 wa.exe,从 in.txt 中读入(<)数据,把结果输出(>)到 wa.txt 中。
system ("fc ac.txt wa.txt") 指的是比较 ac.txt 和 wa.txt ,如果两个文件里的数据相同返回 0,不同返回 1。
那么,我们就可以执行这一操作来实现对拍。
先让数据生成器输出数据。 system ("data.exe> in.txt")
然后用这个数据跑一遍暴力代码,输出结果。 system ("ac.exe < in.txt> ac.txt")
再用这个数据跑一遍你写的正解代码,输出结果。 system ("wa.exe < in.txt> wa.txt")
把两个结果相比较,判断是不是一样的。 system ("fc ac.txt wa.txt")
创建一个源代码,命名为 duipai.cpp:
#include<bits/stdc++.h> | |
using namespace std; | |
int main() | |
{ | |
while (1) // 一直循环,直到找到不一样的数据 | |
{ | |
system("data.exe > in.txt"); | |
system("baoli.exe < in.txt > baoli.txt"); | |
system("std.exe < in.txt > std.txt"); | |
if (system("fc std.txt baoli.txt")) // 当 fc 返回 1 时,说明这时数据不一样 | |
break; // 不一样就跳出循环 | |
} | |
return 0; | |
} |
# 以下是林浩老师的代码
#include<cstdio> | |
#include<cstdlib> | |
#include<ctime> | |
#include<windows.h> | |
int main() | |
{ | |
long s, t; | |
int num = 1; | |
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
while (1) | |
{ | |
system("cls"); | |
do | |
{ | |
system("data.exe > in.txt"); // 数据生成程序 | |
s = clock(); | |
system("wa.exe < in.txt > wa.txt"); // 自己程序 | |
t = clock(); | |
system("ac.exe < in.txt > ac.txt"); // 答案 | |
if (system("fc wa.txt ac.txt > nul")) | |
{ | |
WORD wr2 = FOREGROUND_RED | FOREGROUND_INTENSITY; | |
SetConsoleTextAttribute(hOut, wr2); | |
printf("P%d ", num); | |
break; | |
} | |
else | |
{ | |
WORD wr2 = FOREGROUND_GREEN | FOREGROUND_INTENSITY; | |
SetConsoleTextAttribute(hOut, wr2); | |
printf("P%d ", num); | |
printf("Accept time: %ldms\n", t - s); | |
} | |
num++; | |
printf("\n\n\n\n"); | |
} | |
while (1); | |
WORD wr2 = FOREGROUND_RED | FOREGROUND_INTENSITY; | |
SetConsoleTextAttribute(hOut, wr2); | |
printf("Wrong Answer time: %ldms\n", t - s); | |
wr2 = 0x00000 | FOREGROUND_INTENSITY; | |
SetConsoleTextAttribute(hOut, wr2); | |
system("fc wa.txt ac.txt"); | |
system("pause > nul"); | |
} | |
} |
# 运行 duipai.exe
最后运行
得到结果后去看 查看是哪组数据出了问题,然后根据数据调试 bug