「笔记」教你如何实现对拍
今天学长来讲了一下对拍,我来整理一下
啥是对拍
首先,对拍是干啥的呢??
对拍,主要是用于在考试或者比赛时的验证,可以通过自己针对性的数据找出程序的错误之处。可以将你打的程序与写的暴力程序比较,验证自己算法或猜想的正确性,也可以在做题时放后台运行,用于检测代码是否存在错误。
比如你在做一道题,你会写暴力,也会写正解,你正解的答案不一定是对的,但是你确定暴力的答案一定是对的,这个时候你就可以打一个对拍程序,用对拍程序验证你写的正解的正确性(同理你也可以打两个暴力验证一下暴力的正确性)
咋实现对拍
那么我们需要准备的程序有几个呢?
-
一定正确的暴力程序(baoli.cpp)
-
等待验证的“正解”(std.cpp)
-
生成数据的程序(rand.cpp)
-
对拍,检查的程序(checker.bat)
然后我们运行baoli.cpp,std.cpp,得到两个exe文件,再新建一个a.in文件,作为它们共同的文件输入源。准备好这7个文件后,我们运行checker.bat,即可进行对拍。
代码是啥
(下面我们以洛谷3378的程序为例)
注:代码均来自attack,有些注释来自搜索
baoli.cpp与std.cpp
这俩东东就需要按题目的要求来编写了
但我们一定要保证baoli.cpp是答案一定正确的暴力程序,同时std.cpp就是待验证的程序。有一个要求就是输入文件需要相同,这里使用freopen
文件名可以由自己决定,但两个cpp文件的输入文件必须相同
baoli.cpp
//暴力写法
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N;
int st[MAXN], l, r;
int main() {
freopen("a.in", "r", stdin);
N = read();
l = 1; r = 0;
while(N--) {
int opt = read();
if(opt == 1) {
int x = read();
st[++r] = x;
} else if(opt == 2){
sort(st + l, st + r + 1);
printf("%d\n", st[l]);
} else {
sort(st + l, st + r + 1);
l++;
}
}
return 0;
}
std.cpp
//使用优先队列
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N;
priority_queue<int, vector<int>, greater<int> >q;
int main() {
freopen("a.in", "r", stdin);
N = read();
int tot = 0;
while(N--) {//O(n)
int opt = read();
if(opt == 1) {
int x = read();
q.push(x);
tot++;
} else if(opt == 2){
if(tot == 0) {
puts("gg");
return 0;
}
printf("%d\n", q.top());
} else {
if(tot == 0) {
puts("gg");
return 0;
}
q.pop();
}
}
return 0;
}
rand.cpp
rand.cpp就是生成数据的程序,生成数据的方法有很多,这里就不细说了,上代码
#include<bits/stdc++.h>
#include<ctime>
using namespace std;
int rnd() {
return rand() << 15 | rand();
}
int tot;
int main() {
freopen("a.in", "w", stdout);
srand((unsigned)time(0));
int N = (rand() % 30) + 1;//[1, 30]
cout << N << '\n';
while(N--) {
int opt = rand() % 3 + 1;//[1, 3]
if(opt == 3 && tot == 0) opt = 1;
if(opt == 2 && tot == 0) opt = 1;
cout << opt << ' ';
if(opt == 1) {
int x = rnd();
cout << x << '\n';
tot++;
} else if(opt == 2){
cout << '\n';
} else {
tot--;
cout << '\n';
}
}
return 0;
}
freopen函数中的文件名可以自己定,但需要与baoli.cpp和std.cpp的文件输入名相同(在示例中,fopen函数的文件名必须为a.in)
checker.bat
其实我们并非只能用checker.bat,也可以直接编写cpp文件,若想了解的去网上搜一下,这里就不写了
下面的是.bat文件的编写,文件名因程序而异
baoli.exe > b.out 指的是baoli.exe运行之后生成b.out文件
同理std.exe > c.out 指的是std.exe运行之后生成c.out文件
然后是进行对比,看有没有差别两文件的内容有差别就会自动停止
:loop
rand.exe
baoli.exe > b.out
std.exe > c.out
fc b.out c.out
if not errorlevel 1 goto loop
pause
下面看一下运行图
在运行过程中,如果没有错误,对拍会自动进行,可以放在后台运行,如果出现错误,对拍会自动停止,按ctrl+c退出,然后你就可以在数据生成的输出源中找到使你程序出错的那一组数据(在示例中即为a.in)
这样对拍就完成啦!