什么是对拍
在计算机编程竞赛中,对拍(Testlib)是一种验证程序正确性的方法。它通常用于检查一个程序的输出是否与另一个程序的输出一致,以确保程序的正确性。
对拍通常涉及以下步骤:
-
编写两个或多个解决同一问题的程序,通常一个是暴力解法,另一个是优化解法。
-
使用相同的测试数据对这些程序进行测试,并比较它们的输出。
-
如果所有程序的输出都一致,那么它们很可能都是正确的。
G++配置
这一步是为了可以直接在命令行窗口使用g++对cpp文件进行编译
1. 安装MinGW(DevCpp文件夹中已内置)
2. 按WIN+R键,打开“运行”对话框,输入sysdm.cpl 打开“系统属性”对话框,“高级”选项卡中,单击“环境变量”按钮
3. 双击进入Path,新建中输入MinGW64\bin的路径
所需命令
下列命令皆可在cmd窗口中输入,文件夹目录中输入cmd即可进入当前文件夹命令行
-
编译:
g++ <code.cpp> -o <code.exe>
,需要替换<code.cpp>
为编译的代码名称,<code.exe>
为编译完成的可执行文件,默认的cpp版本可能较老,可以在后追加--std=c++11
。 -
执行:
<code.exe> < <input> > <output>
,<code.exe>
为编译完成的可执行文件,<input>
为输入的文件,<output>
为输出的文件。 -
对比:
fc <out1> <out2>
,<out1>
和<out2>
为需要对比的两个文件。
对拍程序
data.cpp
用于生成符合题意的随机数据,force.cpp
为已知正确的代码,std.cpp
为待验证代码
在C++中,system
函数是一个标准库函数,用于执行操作系统命令。它接受一个字符串参数,该参数包含要执行的命令。当调用system
函数时,程序会暂时停止执行,直到操作系统执行完命令并返回结果
#include <iostream>
using namespace std;
int main() {
system("g++ data.cpp -o data.exe --std=c++11"); // 编译data文件
system("g++ std.cpp -o std.exe --std=c++11"); // 编译 std文件
system("g++ force.cpp -o force.exe --std=c++11"); // 编译force文件
int rp = 0;
while (!rp) {
system("data.exe > input.txt"); // 生成数据,将结果存储在 input.txt中
system("force.exe < input.txt > fout.txt"); // 调用暴力代码,将结果存储在 fout.txt 中
system("std.exe < input.txt > sout.txt"); // 调用对比代码,将结果存储在 sout.txt 中
rp = system("fc fout.txt sout.txt"); // 进行对比
if (rp == 0) cout << "AC" << endl;
else cout << "WA" << endl;
}
return 0;
}
随机数据生成
下面收录了几种可能使用到的随机数据生成
#include <iostream>
#include <cstdlib> // rand(), srand()
#include <ctime> // time()
#include <set>
#include <vector>
#include <algorithm> // shuffle
#include <utility> // pair
using namespace std;
int random(int n) {//返回0-n-1之间的随机整数
cout << rand() % n << '\n';
}
void generateRandomArray() {//随机生成长度为n的绝对值在1e9之内的整数序列
int n = random(1e5) + 1;
int m = 1e9;
for (int i = 1; i <= n; i++) {
cout << random(2 * m + 1) - m << '\n';
}
}
void generateIntervals() {//随机生成 m个[1,n]的子区间
int m = 10, n = 100;
for (int i = 1; i <= m; i++) {
int l = random(n) + 1;
int r = random(n) + 1;
if (l > r) swap(l, r);
cout << l << " " << r << '\n';
}
}
void generateTree() {//随机生成一棵n个点的树,用n个点n-1条边的无向图的形式输出
int n = 10;
for (int i = 2; i <= n; i++) {//从2 ~ n之间的每个点i向 1 ~ i-1之间的点随机连一条边
int fa = random(i - 1) + 1;
int val = random(1e9) + 1;
cout << fa << " " << i << " " << val << '\n';
}
}
void generateGraph() {//随机生成一张n个点m条边的无向图,图中不存在重边、自环
int n = 10, m = 6;
set<pair<int, int>> edges;//防止重边
for (int i = 1; i <= n; i++) {//先生成一棵树,保证连通
int fa = random(i - 1) + 1;
edges.insert({ fa, i + 1 });
edges.insert({ i + 1, fa });
}
while (edges.size() < m) {//再生成剩余的 m-n+1 条边
int x = random(n) + 1;
int y = random(n) + 1;
if (x != y) {
edges.insert({ x, y });
edges.insert({ y, x });
}
}
// Shuffling and outputting
vector<pair<int, int>> Edges(edges.begin(), edges.end());
random_shuffle(Edges.begin(), Edges.end());
for (auto& edge : Edges) {
cout << edge.first << " " << edge.second << '\n';
}
}
int main() {
srand(time(0));
/*随机生成*/
return 0;
}