对拍

对拍是什么

对拍,是一个比较实用的工具,可以用于比较两个文件的输出结果,进而验证自己的代码正确性。
有的时候,你在做一道题,通过了样例,交上却WA了;
有的时候,你有正解思路,却不知道自己打的对不对;
这时候,如果你手头有一份保证正确的暴力代码或题解,那么我们可以自己造数据来测试,让暴力先跑一遍,自己打的正解再跑一遍,然后对比答案;若测试了很多组数据答案都相同,那这个正解大概率没问题;反之,我们就得到了一组测试数据共我们调试。
这,就是对拍。

对拍的实现

1.代码准备

我们要有两份代码,一份“完全正确的暴力或题解”,另一份“你写的正解”;
以下以 A + B 为例进行解释:
正解(待测试)代码:待测试.cpp

#include<iostream>
using namespace std;
int main(){
	int a,b;
	cin>>a>>b;
	if(a<=100&&b<=100)cout<<a+b;
	else cout<<"我不会,长大以后再来学习";
	return 0;
}

暴力代码:暴力.cpp

#include<iostream>
using namespace std;
int main(){
	int a,b;
	cin>>a>>b;
	int ans=0;
	for(int i=1;i<=a;i++){
		ans++;
	}
	for(int j=1;j<=b;j++){
		ans++;
	}
	cout<<ans;
	return 0;
}

两份代码有了后,将它们全部编译,并放在同一文件夹下;
这算是做好了对拍的准备。

2.数据生成器

那么显然,我们不能自己手搓上万组数据;
还好,c++自带一个函数rand(),储存在<cstdlib>头文件中,用于生成随机数。
于是我们得到代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int a=rand(),b=rand();
	cout<<a<<" "<<b;
	return 0;
}

接下来你就会发现,连续运行几次程序,数据都是相同的;
原因在于,rand( )使用的是一个固定的种子,每次运行输出的都是由这个种子产生的序列,所以我们要手动更改种子;
即:srand(time(0)),这句会应用当前时间作为种子,做到一定程度上的真正随机;
但time(0)获得的时间以秒为单位,若在短时间内连续获取,则会浪费大量对拍次数;
所以我们引入_timeb生成毫秒级别:

struct _timeb T;
_ftime(&T);
srand(T.millitm); 

这样就可以了。
对于生成随机数的范围,我们可以采取以下方法来生成一个a到b的随机数:
rand()%(b-a+1)+a
或者直接宏定义:#define rand(a,b) (rand()%((b)-(a)+1)+(a))
这样,我们就有了一套随机数据生成器:

#include<bits/stdc++.h>
#define rand(a,b) (rand()%((b)-(a)+1)+(a))
using namespace std;
int main(){
	struct _timeb T;
	_ftime(&T);
	srand(T.millitm);
//	srand(time(0));上面这个是毫秒级的定种,下面这个也行 
	int a=rand(1,200),b=rand(1,200);
	cout<<a<<" "<<b;
	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

所以:

#include<bits/stdc++.h>
using namespace std;
int main(){
	while(1){
		system("测试点生成器.exe > test.txt");
		system("暴力.exe < test.txt > 暴力.txt");
		system("待测试.exe < test.txt > 待测试.txt");
		if(system("fc 暴力.txt 待测试.txt"))break;
	}
	return 0;
}

程序结束后,test.txt 中存的就是样例,暴力.txt是答案,待测试.txt是你的程序输出的错误答案;

文件输入输出

优点:不用删 freopen 等文件输入输出指令
简单地讲,就是把文件的打开,读写的操作分别打到测试点生成器,暴力,待测试正解中。

暴力
#include<iostream>
using namespace std;
int main(){
	freopen("test.txt","r",stdin);
	freopen("暴力.txt","w",stdout);
	int a,b;
	cin>>a>>b;
	int ans=0;
	for(int i=1;i<=a;i++){
		ans++;
	}
	for(int j=1;j<=b;j++){
		ans++;
	}
	cout<<ans;
	return 0;
}
待测试正解
#include<iostream>
using namespace std;
int main(){
	freopen("test.txt","r",stdin);
	freopen("待测试.txt","w",stdout);
	int a,b;
	cin>>a>>b;
	if(a<=100&&b<=100)cout<<a+b;
	else cout<<"我不会,长大以后再来学习";
	return 0;
}
测试点生成器
#include<bits/stdc++.h>
#define rand(a,b) rand()%((b)-(a)+1)+(a)
using namespace std;
int main(){
	freopen("test.txt","w",stdout);
	struct _timeb T;
	_ftime(&T);
	srand(T.millitm);
	int a=rand(1,200),b=rand(1,200);
	cout<<a<<" "<<b;
	return 0;
}

对拍代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	while(1){
		system("测试点生成器.exe");
		system("暴力.exe");
		system("待测试.exe");
		if(system("fc 暴力.txt 待测试.txt"))break;
	}
	return 0;
}

运行对拍程序

  1. 将四份文件放于同一文件夹下

  2. 运行对拍程序:
    image
    这样就是没问题;
    如果找不到差错,那它就会一直拍着;
    image
    这样就是出错了。

  3. 此时的test.txt中存的就是样例
    image

    而“暴力”中就是正确答案,“待测试”中是错误解答
    image
    image

美化对拍

我们可以给对拍加一些花样,让它能体现出时间,算出分数,等等:

//对拍程序 
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
double be,ed,t;
int ok;
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		system("测试点生成器.exe");
		be=clock();
		system("待测试.exe"); //你要测试的文件 输出至“待测试.txt”
		ed=clock();
		t=(ed-be);
		system("暴力.exe");//你保证对的暴力或题解 输出至“暴力.txt”
		if(system("fc 待测试.txt 暴力.txt")){
			printf("测试点%d WA\n\n",i);
			system("pause");//错解出现时暂停,酌情打开 
		}
		else if(t>1000){
			printf("测试点%d TLE 总用时%.0lfms\n\n",i,t);
			system("pause");//超时时暂停,酌情打开  
		}
		else{
			printf("测试点%d AC 总用时%.0lfms\n\n",i,t);
			ok++;
		} 
	}
	double res=100.0*ok/n;
	printf("\n共%d组数据,AC数据%d组,得分%.1lf",n,ok,res);
	return 0;
} 

image

总结

相信经过上面的过程,大家对“对拍”也有了一定的了解,也能用其解决一些实际问题;
在考场上,对于那些比较容易打出暴力的题,我们就很容易用对拍检验自己代码的正确性;而对拍也能算出程序的用时,以防结束提交评测时全TLE
但对拍也有一定局限,如对于一些大数据,暴力可能所需时间过长,自己的程序也要承受更大压力;所以,要想过大数据,最好还是不要依赖对拍,自己找出代码中的错误,如是否忘开long long等;
总之,对拍是个非常实用的工具,是查错的神器,一定要掌握!
最后,祝所有HE考生们2024省选发挥超常,RP++!

posted @ 2024-02-20 19:55  萝卜甜了  阅读(475)  评论(2编辑  收藏  举报