前置知识
引入
假设你现在正站在某大型比赛的赛场上,面对着屏幕前的世纪难题大汗淋漓,对正解毫无思路,这时你应该怎么办呢?
在这样的情况下,你应该写出一个暴力代码,尝试骗得一部分分数。
然而,不甘于平凡的你怎能只获得可怜的 20 p t s 20pts 20pts呢?你要拿 100 p t s 100pts 100pts。
你绞尽脑汁,想到了一个“疑似正解”,这时你要怎么确定它是否是正解呢?
为了你的宏图伟业,你就要学习这样一种东西:对拍
对拍
对拍是干什么用的呢?
你写了一个暴力和一个“疑似正解”,你确定你的暴力是正确的,这时你要确定你的“疑似正解”是否正正确,这时你需要将暴力和“疑似正解”都输入相同的数据,看它们的输出是否相同。如果对于很多组数据都有相同的输出,我们就可以认为这个“疑似正解”应该就是正确的。
对拍由四部分组成:
- 一个随机数据生成器
- 你的暴力
- 你的“疑似正解”
- 对拍程序
我们以世纪难题为例,来尝试实现对拍。
首先,我们需要一个数据,注意,这个数据的范围不与题目的数据范围相同,而是要根据你的暴力,你的暴力要很快的将这个数据运行完毕,这样才能保证对拍的效率。
为了保证每次生成的数据都不同,我们要进行随机取值。具体参见随机数。
我们将产生数据的代码命名为shujv.cpp
,那么它编译出的EXE文件为shujv.exe
,我们还要将产生的数据输出到一个TXT文件里,命名为shujv.txt
。
shujv.cpp
内容如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
srand(time(0));
freopen("shujv.txt","w",stdout);
int a=rand()%1000+1;
int b=rand()%1000+1;
cout<<a<<' '<<b<<endl;
return 0;
}
然后是你的暴力文件,命名为baoli.cpp
,可执行文件为baoli.exe
,读入数据为shujv.txt
,输出数据为baoli.txt
:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
freopen("shujv.txt","r",stdin);
freopen("baoli.txt","w",stdout);
int a,b;
cin>>a>>b;
int c=0;
for(int i=1;i<=a;i++)
c++;
for(int i=1;i<=b;i++)
c++;
cout<<c;
return 0;
}
“疑似正解”文件同理,为std.cpp
、std.exe
、shujv.txt
、std.txt
:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
freopen("shujv.txt","r",stdin);
freopen("std.txt","w",stdout);
int a,b;
cin>>a>>b;
cout<<a+b;
return 0;
}
这时,就是最关键的部分了:对拍程序!我们要重复执行下面的步骤:
- 制造数据,即运行
shujv.exe
文件 - 运行
baoli.exe
- 运行
std.exe
- 判断
baoli.txt
和std.txt
是否相同
对于前三条,只需要使用system
打开即可,而第四条,则需要使用fc
指令,详见代码:
#include<windows.h>
using namespace std;
int main()
{
while(1)
{
system("shujv.exe");
system("baoli.exe");
system("std.exe");
if(system("fc baoli.txt std.txt"))//判断是否相同
break;//若不同则跳出
}
return 0;
}
全部完成后,文件如下:
这时我们要把除了对拍程序外的所有程序运行一遍,产生EXE文件:
然后运行对拍程序,如果顺利,如下:
如果如上图,恭喜你,你的正解没问题。
如果出现错误,程序会停止:
这时你就可以打开数据寻找错误了。