对拍-验证的重要手段

对拍的C++代码实现

Posted by Marlin on May 1, 2025

前言

在算法竞赛和编程中,对拍(Diff Testing)是一种高效验证代码正确性的方法。它通过对比暴力解法(Brute Force)和优化解法(Optimized Solution)的输出,快速发现逻辑错误。本文将提供完整的C++对拍代码,并逐步讲解其实现原理,帮助你轻松应用到自己的项目中。

对拍的实现

  1. 你想要测的方法a
  2. 实现复杂度不好但是正确的暴力解法b
  3. 实现一个随机样本产生器(长度随机,值也随机)
  4. 把方法a和方法b跑相同的输入样本,看看得到的结果是否一样
  5. 如果有一个随机样本使得方法a和方法b的结果不一致,说明存在问题,需要进一步分析
  6. 当样本数量很多时对比依然正确,可以确定方法a(最优解)已经正确

对拍的基本组成

一个完整的对拍系统需要以下部分:
暴力解法程序(baoli.cpp):保证正确但效率较低,用于生成标准答案。
待测优化程序(zhengjie.cpp):需要验证的高效算法。
随机数据生成器(makedata.cpp):生成合法输入数据。
对拍脚本(duipai.cpp):自动化运行并对比结果。

使用方法

直接运行duipai.cpp即可。它会自动运行随机数据生成器makedata.cpp,生成合法输入数据,运行暴力解法程序baoli.cpp和优化解法程序zhengjie.cpp。对比结果,验证输出结果是否一致。如果结果不一致,则输出错误信息,并输出测试数据和结果。

C++代码实现-以排序为例

1. 暴力解法程序(baoli.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> nums(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> nums[i];
    }
    for (int i = 1; i <= n; i++) { // 冒泡排序
        for (int j = i + 1; j <= n; j++) {
            if (nums[i] > nums[j]) {
                swap(nums[i], nums[j]);
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << nums[i] << " ";
    }
    return 0;
}

作用:提供一个绝对正确的解法(即使时间复杂度较高),用于验证优化程序的正确性。

2. 待测优化程序(zhengjie.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> nums(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> nums[i];
    }
    sort(nums.begin() + 1, nums.begin() + n + 1); // 快速排序
    for (int i = 1; i <= n; i++) {
        cout << nums[i] << " ";
    }
    return 0;
}

作用:提供一个需要验证的高效算法,用于对比暴力解法的正确性。

3. 随机数据生成器(makedata.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <bits/stdc++.h>
using namespace std;

int main() {
    std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); // 随机数生成器
    int n = rng() % 100 + 1; // 数组的长度范围为[1, 100]
    int v = 1000; // 数组中的数据范围为[0, v)
    cout << n << endl;
    for (int i = 1; i <= n; i++) {
        cout << rng() % v << " "; // 随机生成[0, v)的整数
    }
    return 0;
}

作用:生成随机输入数据,确保测试覆盖各种边界情况(如负数、0、最大值等)。

4. 对拍主程序(duipai.cpp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <bits/stdc++.h>
using namespace std;

int main() {
    system("g++ -std=c++11 baoli.cpp -o baoli.exe");
    system("g++ -std=c++11 zhengjie.cpp -o zhengjie.exe");
    system("g++ -std=c++11 makedata.cpp -o makedata.exe");

    while (1) {
        system("makedata.exe > makedata.txt");
        system("baoli.exe < makedata.txt > baoli.txt");
        system("zhengjie.exe < makedata.txt > zhengjie.txt");

        if (system("fc baoli.txt zhengjie.txt")) {
            cout << "Wrong Answer" << endl;
            system("type makedata.txt");
            system("type baoli.txt");
            system("type zhengjie.txt");
            break;
        } else {
            cout << "Accepted" << endl;
        }
    }

    return 0;
}

作用:自动运行暴力解法和优化解法,对比结果,输出结果是否一致。

总结

对拍是一种高效验证代码正确性的方法,通过对比暴力解法和优化解法的输出,快速发现逻辑错误。本文介绍了对拍的基本组成,并给出了C++对拍代码的实现。希望能帮助你轻松应用到自己的项目中。