信息学竞赛对拍器的设计

信息学竞赛中,很多时候我们需要检验需要提交程序的正确性,但手动测试有太慢而且不准确。

所以我们可以写两个程序,一个用于提交,另一个测试(通常是比较正确但是往往用暴力写的,会超时),

当然写对拍器之前要写数据生成器,以后介绍,这是最简单的A+B Problem的数据生成器:

#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("in.txt","w",stdout);//请根据需要自行修改数据生成代码 
	int a,b;
	srand(time(0));
	a=rand();
	b=rand();
	printf("%d %d",a,b);
	return 0;
}

对拍器就是用于测试数据并比较两程序的输出是否相同的程序,下面介绍对拍器的写法:

方法一:

代码如下(程序B):

@echo off
set cnt=0
for /l %%i in (1,1,10) do ( 
::相当于for(int i = 1;i <= 10;i++) ,可以修改第三个数字来改变测试次数
  randdata.exe
  std.exe
  mine.exe
  fc out1.txt out2.txt >result.txt
  if errorlevel 1 ( ::如果发现不一致
    set cnt=1
    echo %%i:UnAccepted!
    pause
  )
  if  not errorlevel 1 echo %%i:Accepted!
)
if %cnt%==0 color a && echo *** Totally Accepted! ***
if %cnt%==1 color c && echo *** Not All Accepted! ***
pause

以上代码是批处理写的,有兴趣的可以学习一下,还是有用的

讲代码拷贝到记事本,然后保存为 xxx.bat 或 xxx.cmd (xxx为文件名),就可以运行了

但是需要遵守以下规则:

I.使用程序A或B每个程序需要添加的语句:
  a.你的程序:
    1.需要把程序名称改为mine.cpp
    2.添加到main函数开头:
freopen("in.txt","r",stdin);
freopen("out1.txt","w",stdout);
  b.标准程序(或暴力正确程序)
    1.把程序名称改为std.cpp
    2.添加到main函数开头:
freopen("in.txt","r",stdin);

freopen("out2.txt","w",stdout);

还有另一种写法(程序C):

@echo off
set cnt=0
for /l %%i in (1,1,10) do (
  randdata.exe
  std.exe < in.txt > out1.txt
  mine.exe < in.txt > out2.txt
  fc out1.txt out2.txt > result.txt
  if errorlevel 1 (
    set cnt=1
    echo %%i:UnAccepted!
    pause
  )
  if not errorlevel 1 echo %%i:Accepted!
)
if %cnt%==0 color a && echo *** Totally Accepted! ***
if %cnt%==1 color c && echo *** Not All Accepted! ***
pause

II.使用程序C需要把freopen语句注释掉,程序名称同I

方法二:

先说方法二的优缺点:程序A界面比B稍友好一些,但有时会判断错误

代码如下(程序A):

on error resume next '忽略所有错误
set obj=createobject("wscript.shell")
set fso=createobject("scripting.filesystemobject")
dim ct,result,cnt
cnt=0
ct=inputbox("请输入需要测试的次数:","提示")
if ct>40 then
  ct=40
  msgbox"测试次数不能大于40,自动改为40次",vbinformation,"提示"
end if
for i=1 to ct
  obj.run"randdata.exe",true		'启动数据生成程序
  obj.run"std.exe",true	'启动标准程序(或暴力但准确性可以保证的程序)
  obj.run"mine.exe",true		'启动你的程序
  obj.run"datacmp.exe",true		'启动对比程序
  set fread=fso.opentextfile("result.txt",1)
  result=fread.readall			'记录测试结果
  fread.close
  if result<>"0" then			'发现错误
    msgbox"发现错误:第" & i & "次测试" & chr(13) & "错误行数:" & result ,16,"提示"
    cnt=cnt+1
  end if
next
obj.run"taskkill -f -im std.exe"
obj.run"taskkill -f -im mine.exe"
obj.run"taskkill -f -im datacmp.exe"
msgbox"测试完毕!" & chr(13) & "共发现" & cnt & "处错误" ,,"结果"
程序CMP:
#include<bits/stdc++.h>
using namespace std;
char x[100],a1[100005][100],a2[100005][100];//可以根据需要修改数组大小 
int main()
{
	freopen("result.txt","w",stdout);
	freopen("out1.txt","r",stdin);
	int i=0,j=1,sum=0;
	while(gets(x)!=0)
	{
		int len=strlen(x);
		if(x[len-1]==' ') x[len-1]='\0';//忽略行尾空格 
		i++;
		strcpy(a1[i],x);
	}
	freopen("out2.txt","r",stdin);
	i=0;
	while(gets(x)!=0)
	{
		int len=strlen(x);
		if(x[len-1]==' ') x[len-1]='\0';//忽略行尾空格 
		i++;
		strcpy(a2[i],x);
	}
	for(j=1;j<=i;j++)
	if(strcmp(a1[j],a2[j])!=0){
//查看错误行内容 
//		printf("error on line %d:\n",j);
//		printf("\tcmp:%s\n\tstd:%s\n",a1[j],a2[j]);
		sum++;
	}
	cout<<sum;
	return 0;
}

同样,程序A用记事本打开,保存为xxx.vbs,程序CMP保存为datacmp.cpp,程序A注释比较详尽,就不多讲了

附:

友情提示:考试时需要自己写对拍器,因此建议读者记忆并能熟练编写数据生成器和对拍器(以下是最简单,也是最实用的版本

@echo off
for /l %%i in (1,1,10) do (
  randdata.exe
  code1.exe < in.txt > out1.txt
  code2.exe < in.txt > out2.txt
  fc out1.txt out2.txt > result.txt
  if errorlevel 1 echo %%i:WA! && pause
  if not errorlevel 1 echo %%i:AC!
)
pause

该对拍器的下载地址:点击打开链接

效果图:



效果图(程序C):



程序A:


猜你喜欢

转载自blog.csdn.net/hi_ker/article/details/80671110
今日推荐