【算法模板】算竞技巧:对拍全解

什么是对拍

在计算机编程竞赛中,对拍(Testlib)是一种验证程序正确性的方法。它通常用于检查一个程序的输出是否与另一个程序的输出一致,以确保程序的正确性。

对拍通常涉及以下步骤:

  1. 编写两个或多个解决同一问题的程序,通常一个是暴力解法,另一个是优化解法。

  2. 使用相同的测试数据对这些程序进行测试,并比较它们的输出。

  3. 如果所有程序的输出都一致,那么它们很可能都是正确的。

G++配置

这一步是为了可以直接在命令行窗口使用g++对cpp文件进行编译

1. 安装MinGW(DevCpp文件夹中已内置)

2. 按WIN+R键,打开“运行”对话框,输入sysdm.cpl 打开“系统属性”对话框,“高级”选项卡中,单击“环境变量”按钮

3. 双击进入Path,新建中输入MinGW64\bin的路径

所需命令

下列命令皆可在cmd窗口中输入,文件夹目录中输入cmd即可进入当前文件夹命令行

  1. 编译: g++ <code.cpp> -o <code.exe>,需要替换 <code.cpp> 为编译的代码名称,<code.exe> 为编译完成的可执行文件,默认的cpp版本可能较老,可以在后追加--std=c++11

  2. 执行: <code.exe> < <input> > <output><code.exe> 为编译完成的可执行文件,<input> 为输入的文件,<output> 为输出的文件。

  3. 对比: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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值