对拍教程

本文将简单介绍对拍的使用方法。

什么是对拍?对拍有什么用?

对拍就是利用一个正确程序和一个未知程序进行多组答案比较,判定未知程序的正确性的方法。

对拍在算法竞赛中也被用于检验两个未知程序的正确性,竞赛中一般可以认为两个可过样例的本质不同的程序能拍出相同结果,等价于两个程序均正确;但注意由于两个程序同样的取模和上下溢出导致的错误可能无法被用对拍检查出。

怎么使用对拍?

以下使用方法中的文件定义(均保存在当前目录下):

  • brute.cpp / brute.exe / brute:“暴力”求解程序(或正确程序)。
  • code.cpp / code.exe / code:待验证程序。
  • generator.cpp / generator.exe / generator:符合两个程序时空复杂度和题目数据范围的数据生成器(基于随机数)。
  • duipai.cpp / duipai.exe / duipai:对拍程序。

以上程序均使用文件读写,其中 *.cpp 是 C++ 语言源代码文件,*.exe 是 windows 下的可执行文件,无后缀名的是 linux 下的可执行文件。

windows 使用方法

编写好程序 brute.cppcode.cppgenerator.cpp 并编译为可执行文件,保存在当前目录下。

编写程序 duipai.cpp,伪代码如下:

1Input. Expected number of test cases n.2Output. The verdict of the code.3Method.4while T1 to n5generate input file with generator.exe6generate answer file with brute.exe7generate output file with code.exe8compare the answer file and the output file9give the verdict

下面是两个常识,有关需要用到的 windows 指令:

重定向程序 test.exe 的输入输出,让它从 1.in 读入并输出到 1.out 的方法是:test.exe < 1.in > 1.outtest < 1.in > 1.out

比较文件 1.out1.ans(忽略空白字符)的方法是:fc 1.out 1.ans。为了排版美观,也可以重定向输出到 1.logfc 1.out 1.ans > 1.log

其中判断是否有差异的方法是,没有差异 fc 的返回值为 0,否则不为 0

本文最后会有示例。

linux 使用方法

实现方法相同,第一个指令改成 ./test < 1.in > 1.out,第二个指令改成 diff 1.out 1.ans 即可。

使用示例(windows)

以 A+B Problem 为例,下面是对拍的一个示例:

brute.cpp

#include <bits/stdc++.h>
using namespace std;

int main() {
    int a, b;
    cin>>a>>b;
    cout<<a+b<<endl;
    return 0;
}

code.cpp

#include <bits/stdc++.h>
using namespace std;

int main() {
    srand(time(0));
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d\n", a+b+(rand()%5==4)); // 故意制造一些错误
    return 0;
}

generator.cpp

#include <bits/stdc++.h>
using namespace std;
const int lim = 1e8;

int myrand(int L, int R) {
    int rnd = rand() << 15 | rand(); // 注意由于 windows 下 rand() 的返回值最大为 32767,为了获得 int 范围内的随机数需要这么做
    if(rnd < 0) rnd = -rnd;
    return rnd % (R - L + 1) + L;
}

int main() {
    srand(time(0));
    int a, b;
    a = myrand(1, lim);
    b = myrand(1, lim);
    printf("%d %d\n", a, b);
    return 0;
}

duipai.cpp (windows)

#include <bits/stdc++.h>
using namespace std;

int main() {
    int expected = 0, verdict = 1;
    printf("Input number of test cases: ");
    scanf("%d", &expected);
    for(int test_case=1;test_case<=expected;test_case++) {
        printf("Running on test #%d: ", test_case);
        if(!verdict) {
            printf("Skipped\n");
            continue;
        }
        system("generator > 1.in");
        system("code < 1.in > 1.out");
        system("brute < 1.in > 1.ans");
        if(system("fc 1.out 1.ans > 1.log")) {
            printf("WA\n");
            verdict = 0;
            continue;
        }
        printf("AC\n");
    }
    if(verdict) printf("Verdict: AC\n");
    else printf("Verdict: WA\n");
    return 0;
}

错误信息可以在 1.log 找到,错误测试点的输入输出和答案在对应的 .in / .out / .ans 文件中。

posted @   rui_er  阅读(538)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示