一、课程目标
- 准备工作
- 编译运行与重定向
- 结果比对
- 数据生成器
- 对拍脚本
- 计时模式
二、目标详解
1、准备工作
1.1 编译工具
首先需要安装gcc/g++的编译工具MinGW32,如果已经安装了devcpp的话,是自带MinGW32的。
1.2 编辑器
需要一个写代码的编辑器,一般用devcpp就好,当然想用别的例如记事本也可以。
1.3 路径配置
对拍要在命令行里面调用gcc/g++命令,需要先配置好path路径。假设devcpp安装在E:\Dev-cpp5.4.0\Dev-Cpp,则g++的目录为E:\Dev-cpp5.4.0\Dev-Cpp\MinGW32\bin,需要将之配置进path。
配置
:
- 打开控制面板,到系统 -> 高级系统设置,弹出“系统属性页”。
- 点“环境变量”按钮弹出“环境变量”窗口
- 在系统变量里面找到Path,点“编辑”按钮,弹出编辑窗口
- 在“变量值”的最后面加上”; E:\Dev-cpp5.4.0\Dev-Cpp\MinGW32\bin”。
- 一路确定。
- 然后打开终端验证(如果已经开着要先关掉再打开)
验证
:windows的运行里打cmd回车,弹出终端,输入g++回车,显示:
- g++ 不是内部或外部命令….,表示没有配置成功
- g++: fatal error: no input files,表示已经配置成功
1.4 cd到代码目录
终端打开的时候,默认工作目录在C:\Users\Administrator(或其它用户名目录)。对拍的时候,终端要cd到代码目录(如E:\code)。
e: //回车切换到E盘
cd code //回车,进入E: \code目录
验证
:用dir命令就可以查看到当前目录,例如:
2、编译运行与重定向
2.1 编译运行
例如代码为hello.cpp(已经编写好代码,读入一行字符串,然后输出),则在windows的终端窗口,执行以下命令:
g++ hello.cpp -o hello.exe //编译
hello.exe //运行
2.2 重定向读
程序的输入:可以用 < 命令重定向到一个文件读取
hello.exe < 1.in
2.3 重定向写
程序的输出:可以用 > 命令重定向写入到一个文件里
hello.exe > 1.out
in和out文件也可以用编辑器来打开(查看、修改),与代码文件同一个目录。
3、结果比对
现在对于某道题,可以手工生成in数据和ans文件,然后调用重定向生成out文件,用
fc命令比对ans文件和out了。
fc命令
:用来比对两个文件内容是否一致,如fc 1.out 1.ans。
如果文件内容一致,显示如下:
如果文件内容不一致,显示如下:
4、数据生成器
数据生成器是根据题目要求编写的代码文件,用来生成符合题目要求的输入数据,保存到in文件里。例如:
g++ data.cpp -o data.exe
data.exe > 1.in
主要是使用rand()函数生成各种随机数据,因此要包含ctdlib和ctime两个头文件。具体例子如下(n个数字的序列):
#include <iosteam>
#include <cstdlib>
#inlcude <ctime>
int main() {
srand(ctime(0)); //用时间做随机种子
int n = rand()%10000+1; //1..10000的随机长度
cout<<n<<endl;
for(int i=1; i<=n; i++) {
int x = rand()%1000+1; //1..1000的随机元素
cout<<x<<" ";
}
return 0;
}
5、对拍脚本
用两份代码,其中一份是朴素代码(正确的),另一份是其它方法实现的(可能是优化代码),循环多次用数据生成器生成随机数据,然后两份代码分别输出结果进行比对,如果完全一致说明对拍通过,否则退出。此时出问题的数据被保存,可以用来调试错误。
@echo off
:loop
data.exe > duipai.in
simple.exe < duipai.in > simple.out
good.exe < duipai.in > good.out
fc /A simple.out good.out
if %errorlevel%==0 goto loop
echo WA
pause
也可以不用批处理,直接用c++编写对拍脚本,如下:
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main(){
for(int i=1;i<=10000;i++){
system("data.exe > duipai.in");
double st=clock();
system("simple.exe < duipai.in > simple.out");
double ed=clock();
system("good.exe < duipai.in > good.out ");
if(system("fc /A simple.out good.out")){
cout<<"WA"<<endl;
return 0;
}
else{
printf("Ac,测试点 #%d, 用时 %.0lfms\n",i,ed-st);
}
}
return 0;
}
三、扩展
1、超过多少次退出
@echo off
set /A cnt = 0
:loop
set /A cnt = %cnt% + 1
if %cnt% GTR 10 (
echo 超过10次,退出
goto end
)
data.exe > duipai.in
simple.exe < duipai.in > simple.out
good.exe < duipai.in > good.out
fc /A simple.out good.out
if %errorlevel%==0 goto loop
echo WA
goto end
:end
pause
2、随机数太慢
srand(time(0))一秒钟产生一个随机数,对拍会比较慢。
在windows脚本里可以用%random%产生随机数,如下修改:
data.exe %random% > duipai.in
同时在data.cpp里也传入参数作为随机数种子:
int main(int argc, char *argv[]) {
if(argc<=1)
srand(time(0));
else {
int seed;
stringstream ss;
ss.clear();
ss<<argv[1];
ss>>seed;
srand(seed);
}
......