对拍
对拍是什么
对拍,是一个比较实用的工具。它能够非常方便地对于两个程序的输出文件进行比较,可以帮助我们实现一些自动化的比较输出结果的问题。
众所周知,几乎每一道编程题目,都会有某种正解能拿到满分;当我们想不出正解时,我们往往可以打暴力代码来获取部分分数。
但是,当我们觉得有思路写正解,但又担心自己正解写的不对,而恰好,我们又有一个能够暴力骗分的代码。这个时候就可以用到对拍。 暴力骗分代码必须保证正确性,只是超出时间限制,不能出现答案错误的情况。
这样,我们可以造多组数据,让暴力骗分的程序跑一遍,再让我们自己写的正解跑一遍,二者进行多次对比。如果多组数据都显示二者的输出结果一样,那么这个正解大概率没问题。相反地,如果两组数据不同,我们就找到了一组错误数据,方便调试,找到正解哪里出了问题。
这便是对拍。其作用也在上文提出。
利用 timeb 生成毫秒级别随机数
众所周知,重复打开相同的可执行文件,想要输出的数不同,往往需要以时间作为随机种子。
如:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
srand(time(0));
int a=rand();
cout<<a<<endl;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)solve();
return 0;
}
制作数据生成器#
前置知识:利用 timeb 生成毫秒级别随机数
我们制作的数据要求格式和上面两份代码的输入格式一样。
根据上面,我们可以知道输入的数据为 2 个数,中间有空格分隔。那么,我们的数据生成器就要输出 2 个数,中间也要用空格分隔。
创建一个新的源代码
点击查看代码
#include <bits/stdc++.h>
int main()
{
struct _timeb T;
_ftime(&T);
srand(T.millitm);
freopen("in.txt", "w", stdout); //生成 使两份基本代码 将要读入的数据
int a = rand(), b = rand();
printf("%d %d\n", a, b);
}
这里有个小问题。Windows 系统下 rand() 生成的随机数的范围在 0~32767 之间。如果我们想要得到比 32767 更大的随机数怎么办呢?除了换 Unix 系统外,我还有一个小办法,很实用。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
ll Random(ll mod)
{
ll ans = 2147483647;
return ans = ans * rand() % mod + 1;
}
int main()
{
struct _timeb T;
_ftime(&T);
srand(T.millitm);
ll n;
while (1)
{
n = Random(1000000);
printf("%lld\n", n);
}
return 0;
}
对拍
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
while (1) //一直循环,直到找到不一样的数据
{
system("data.exe");
system("baoli.exe");
system("std.exe");
if (system("fc std.txt baoli.txt")) //当 fc 返回 1 时,说明这时数据不一样
break; //不一样就跳出循环
}
return 0;
}
标准输入输出代码
标准输入输出指的是:两份基本代码和数据生成代码里不含文件输入输出操作,如 freopen 等。
在这里,我们需要用到一些文件的读写符号。(需用到
system("A.exe > A.txt") 指的是运行 A.exe,把结果输出(>)到 A.txt 中。
system("B.exe < A.txt > C.txt") 指的是运行 B.exe,从 A.txt 中读入(<)数据,把结果输出(>)到 C.txt 中。
system("fc A.txt B.txt") 指的是比较 A.txt 和 B.txt ,如果两个文件里的数据相同返回0,不同返回1。
那么,我们就可以执行这一操作来实现对拍。
先让数据生成器输出数据。 system("data.exe > in.txt")
然后用这个数据跑一遍暴力代码,输出结果。 system("baoli.exe < in.txt > baoli.txt")
再用这个数据跑一遍你写的正解代码,输出结果。 system("std.exe < in.txt > std.txt")
把两个结果相比较,判断是不是一样的。 system("fc std.txt baoli.txt")
点击查看代码
#include <iostream>
#include <cstdio>
#include <windows.h>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
int ok = 0;
int n = 50;
for (int i = 1; i <= n; ++i)
{
system("data.exe > in.txt");
system("std.exe < in.txt > std.txt");
double begin = clock();
system("baoli.exe < in.txt > baoli.txt");
double end = clock();
double t = (end - begin);
if (system("fc std.txt baoli.txt"))
{
printf("测试点#%d Wrong Answer\n", i);
}
else if (t > 1000) //1秒
{
printf("测试点#%d Time Limited Exceeded 用时 %.0lfms\n", i, t);
}
else
{
printf("测试点#%d Accepted 用时%.0lfms\n", i, t);
ok++; //AC数量+1
}
}
printf("\n");
double res = 100.0 * ok / n;
printf("共 %d 组测试数据,AC数据 %d 组。 得分%.1lf。", n, ok, res);
}