对拍是OI系列赛事常用的检验方法之一,它用来检验自己写的“正解”到底正不正确。简要的说,就是用一个脚本文件比对两个输出结果来判断正确性。
要使用对拍,必须要有一个保证正确的暴力程序作为参照,这个程序虽然正确,但是由于时间复杂度较高所以无法拿到很高的分数,一般是拿到题后首先想到的比如暴力搜索之类的算法。而我们要比对的程序就是自己在冷静分析后所写出来的所谓“正解”,如果你无法证明这个算法是显然正确的,那么对拍就可以帮助你验证它的正确性。
那么对拍需要准备的工具都是啥呢?
首先,我们需要两个源程序,第一个是作为参照的暴力程序,第二个是我们写完的所谓“正解”但正确性未知的程序。
既然要比对输出,那么比较工具自然少不了,这个比较工具就是上面我说的脚本文件,不过这个东西并不是用C++语言写出来的。简要来说,它接收一个输入数据,然后分别在两个程序中运行,然后判断输出结果是不是一致。如果你的正解和暴力解法输出不一致,那么你的解法就有可能存在问题。
其实还缺一个最重要的东西,那就是数据生成器。巧妇难为无米之炊,比较器如果没有输入数据是没办法比较的,所以我们还得根据输入格式自己制造数据。
这就牵扯到随机数生成的问题了,我在之前的博客里使用过随机数生成的程序,我记得当时应该是用来做读入性能测试。我再后来给学校暑期模拟赛出题,自己造数据的时候也用到过随机数生成。
两个比对程序是根据题目自己写出来的,这个因题而异,我在这里用A+B问题举例。
我们知道,在实际的比赛中要使用文件操作,对拍程序也需要程序的输入和输出文件来进行比较(当然有重定向版本的对拍脚本不需要文件,我这个不是。。)
首先我写了一个作为标准的程序。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 int a,b; 5 int main(){ 6 freopen("randdata.out","r",stdin); 7 freopen("std.out","w",stdout); 8 cin >> a >> b; 9 cout << a + b << endl; 10 return 0; 11 }
这个a+b没毛病吧。
然后我故意制造一个bug。
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 int a,b; 5 int main(){ 6 freopen("randata.out","r",stdin); 7 freopen("problem.out","w",stdout); 8 cin >> a >> b; 9
10 if (a+b > 1926) 11 cout << "-1" << endl; 12 else 13 cout << a+b << endl; 14 15 return 0; 16 }
可以看出,它们都读入一个叫randdata.out的文件,这个文件就来源于下面这个程序。
#include <cstdlib> #include <cstdio> #include <ctime> #include <iostream> #include <unistd.h> #include <windows.h> #define random(x) (rand()%x+1) using namespace std; int main(){ srand(time(NULL)); int a,b; a = random(2000); b = random(2000); freopen("randdata.out","w",stdout); printf("%d %d",a,b); return 0; }
具体要生成什么格式的数据还是就题论题,但大体的思路还是一致的,即随机数生成。
如果要生成一个合法的树或者图,可能需要一些算法。我如果没记错的话luogu有一个开源的数据生成器CYaRon,那里面有pyhton3.x版本的生成这些数据结构的代码,借鉴思想后将其转换至C++语言是一个不错的方法,您大可拿来一试。
对拍所用的脚本其实是根据系统的不同而有差异的,在windows下的脚本和在linux下的脚本写法不太一样。
我并不是一个linux用户(以后不一定不是),所以linux版本的对拍脚本并不是很熟悉,这里只提供windows版本的对拍脚本,有兴趣研究linux下对拍者请自行查阅其他资料。
下面是windows下对拍脚本一般写法。
@echo off :start randdata.exe problem.exe std.exe @echo %time% fc problem.out std.out if not errorlevel 1 goto start pause
@echo命令我记得是防止信息重复输出的。:start相当于一个记号,下面三个.exe文件就是我们编译之后的源程序,你应该先执行数据生成器程序,再执行两个等待评判的程序。
如果一切正常,那么这个时候三个程序都会输出一个.out文件。
倒数第三行的fc命令便是鉴别两个文件是否不同,如果两个文件相同,那么就再回到start再生成一次数据测试。
倒数第四行为输出时间,可以不加。
如果找到不同,那么就pause了。
最后,上述可执行程序和对拍脚本应该放在同一文件夹下执行,否则不能执行。
如果您对对拍代码难以理解,那还请您背过,因为它很重要,这是在考场上为数不多的检验自己程序正确性的方式。