C++ 对拍详解

这篇具有很好参考价值的文章主要介绍了C++ 对拍详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

对拍是什么

​对拍,是一个比较实用的工具。它能够非常方便地对于两个程序的输出文件进行比较,可以帮助我们实现一些自动化的比较输出结果的问题。

​众所周知,每一道编程题目,都会有某种正解能拿到满分;当我们想不出正解时,我们往往可以打暴力代码来获取部分分数。

​但是,当我们觉得有思路写正解,但又担心自己正解写的不对,而恰好,我们又有一个能够暴力骗分的代码。这个时候就可以用到对拍。 暴力骗分代码必须保证正确性,最多只是超时,不能出现答案错误的情况。

​这样,我们可以造多组数据,让暴力骗分的程序跑一遍,再让我们自己写的正解跑一遍,二者进行多次对比。如果多组数据都显示二者的输出结果一样,那么这个正解大概率没问题。相反地,如果两组数据不同,我们就找到了一组错误数据,方便调试,找到正解哪里出了问题。

​这便是对拍。其作用也在上文提出。

对拍的实现

准备基本代码

​首先,我们要有2份代码,一份是这一道题“你写的正解”代码,另一份是同一道题“你打的暴力”代码。

​为了方便,我们先用 A+B problem 来演示对拍。

​自己的代码: std.cpp

#include <cstdio>
using namespace std;
int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    printf("%d\n", a + b);
    return 0;
}

​暴力代码:baoli.cpp

#include <cstdio>
using namespace std;
int main()
{
    int a, b;
    scanf("%d%d", &a, &b);
    int ans = 0;
    int i;
    for (i = 1; i <= a; i++)
        ans++;
    for (i = 1; i <= b; i++)
        ans++;
    printf("%d\n", ans);
    return 0;
}

​两份代码有了,我们把它放在同一个文件夹里。这样算是做好了对拍的准备。

 c++对拍,c++,算法,图论

 

制作数据生成器

我们制作的数据要求格式和上面两份代码的输入格式一样。

​根据上面,我们可以知道输入的数据为2个数,中间有空格分隔。那么,我们的数据生成器就要输出2个数,中间也要用空格分隔。

#include <cstdio>
#include <cstdlib>
#include <ctime>
int main()
{
    srand(time(0));
    //这是一个生成随机数随机种子,需要用到 ctime 库
    printf("%d %d\n", rand(), rand());
    //这样就生成了2个随机数
    return 0;
}

运行一下,确实生成了2个随机数。

c++对拍,c++,算法,图论

 

​注:如果不加那个随机种子,生成的随机数每次都是一样的数。

Extra:数据范围

​如果我们对于数据范围有要求,那怎么办呢?

​要让随机数限定在一个范围,可以采用 “模除加加法” 的方式。

​对于任意数,0≤rand()%(a+1)≤a 。

​于是 0+k≤rand()%(a+1)+k≤a+k 。

​举几个简单的例子:

  1. 当 a=rand()%2 时,a 的范围:0≤a≤1 。
  2. 当 a=rand()%2+1 时,a 的范围:1≤a≤2 。
  3. 要想让 1≤a≤30000 ,则 a=rand()%30000+1 。

但是,这里有个小问题。Windows 系统下 rand() 生成的随机数的范围在0~32767之间。如果我们想要得到比32767更大的随机数怎么办呢?除了换 Unix 系统外,我还有一个小办法,很实用。

比如让 1≤a≤1,000,000

ll random(ll mod)
{
    ll n1, n2, n3, n4, ans;
    n1 = rand();
    n2 = rand();
    n3 = rand();
    n4 = rand();
    ans = n1 * n2 % mod;
    ans = ans * n3 % mod;
    ans = ans * n4 % mod;
    return ans;
}

int main()
{
    srand((unsigned)time(0));
    ll n;
    while (1)
    {
        n = random(1000000);
        cout << n << endl;
    }
    return 0;
}

看一下输出结果

c++对拍,c++,算法,图论

 

这种 “暴力” 的方法是不是感到很神奇呢?

对拍代码

标准输入输出代码

​标准输入输出指的是:两份基本代码和数据生成代码里不含文件输入输出操作,如 freopen 等。

​在这里,我们需要用到一些文件的读写符号。(需用到 库)

​system(“A.exe > A.txt”) 指的是运行 A.exe,把结果输出(>)到 A.txt 中。

​system(“B.exe < A.txt > C.txt”) 指的是运行 B.exe,从 A.txt 中读入(<)数据,把结果输出(>)到 C.txt 中。

​system(“fc A.txt B.txt”) 指的是比较 A.txt 和 B.txt ,如果两个文件里的数据相同返回0,不同返回1。

​那么,我们就可以执行这一操作来实现对拍。

  1. 先让数据生成器输出数据。 system(“data.exe > in.txt”)
  2. 然后用这个数据跑一遍暴力代码,输出结果。 system(“baoli.exe < in.txt > baoli.txt”)
  3. 再用这个数据跑一遍你写的正解代码,输出结果。 system(“std.exe < in.txt > std.txt”)
  4. 把两个结果相比较,判断是不是一样的。 system(“fc std.txt baoli.txt”)

文件输入输出

​标准输入输出指的是:两份基本代码和数据生成代码里含有文件输入输出操作,如 freopen 等。

​因为基本代码中有文件输入输出,所以我们在对拍代码中不必使用 ‘ < ‘ 、’ > ‘ 等符号对文件进行操作。只需运行一下两个程序,程序会自己输出文件。

​这种文件输入输出的模式适合各种大型线下比赛使用。优点在于对拍的时候不用删除 freopen 。

1. 数据生成代码例子:

#include <bits/stdc++.h>
int main()
{
    srand(time(0));
    freopen("in.in", "w", stdout); //生成 使两份基本代码 将要读入的数据
    int a = rand(), b = rand();
    printf("%d %d\n", a, b);
}

2. 暴力代码例子:

#include <bits/stdc++.h>
int main()
{
    freopen("in.in", "r", stdin);      //读入数据生成器造出来的数据
    freopen("baoli.txt", "w", stdout); //输出答案
    int a, b, ans = 0;
    scanf("%d %d", &a, &b);
    for (int i = 1; i <= a; ++i)
        ans++;
    for (int i = 1; i <= b; ++i)
        ans++;
    printf("%d\n", ans);
}

3. 正解代码例子:

#include <bits/stdc++.h>
int main()
{
    freopen("in.in", "r", stdin);
    freopen("std.txt", "w", stdout);
    scanf("%d %d", &a, &b);
    printf("%d\n", a + b);
}

4. 对拍代码

#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
    while (1) //一直循环,直到找到不一样的数据
    {
        system("data.exe");
        system("baoli.exe");
        system("std.exe");
        if (system("fc std.txt baoli.txt")) //当 fc 返回1时,说明这时数据不一样
            break;                          //不一样就跳出循环
    }
    return 0;
}

运行对拍程序

​目前,我们有了4份代码。为了实现对拍,我们要把这些代码放在同一个文件夹的同一层里。

​并且打开每一份代码,让每一份代码都生成一个同名的 .exe 程序。如下:c++对拍,c++,算法,图论

 

​然后,打开 duipai.exe ,我们可以看到程序正在对两个输出文件进行比较

c++对拍,c++,算法,图论

 

​找不到差异,说明这两份代码输出的两个文件是一样的。

​那么我们可以一直拍着,如果长时间都是找不到差异,那么你写的正解就可能是对的了。

​如果找到差异,它会分别返回两个文件的数据,这样我们就有了一组错误数据,方便我们 debug 。

c++对拍,c++,算法,图论
这是存在差异的情况。

 

程序的优化

节约对拍次数

​在对拍时,你有没有发现在 cmd 的黑色框框里面,“找不到差异” 这几行输出的很快,看起来对拍的频率好像很高的样子。实际上,这样浪费了很多次对拍,数据生成需要一定的时间,而文件的读取输出等都需要一定时间。但是两个输出文件的对比却在不停地运行着,数据生成器生成的文件在一定的时间内是相同的,这样就浪费了许多次对拍。

​为此,我们可以使每次对拍完毕后休眠1秒,给四个程序留给一定的缓冲时间,使得每次对拍时,数据生成器生成的数据都不同。

​那么,我们可以使用 <windows.h> 库里的 Sleep(t) ,t 为时间,单位是毫秒。它可以使程序休眠 t 毫秒。我们可以在每次对拍之后加上 Sleep(1000) ,这样每次对拍之后休眠1秒,就不会出现浪费对拍的情况了。详见下面代码部分。

美化对拍程序

​众所周知,每一道编写程序题都有时间限制。那么我们可以用一个计时函数”clock()”,来计算我们写的正解用的时间,判断它是否超时(当然,本地测出的时间和评测机测的时间一般不同),并把所用时间在对拍程序上体现出来。

​我们还可以给把一个通过的数据当作一个测试点,还可以给他赋予编号,这些都能在对拍程序直观地体现出来,像下面这样:

#include <iostream>
#include <cstdio>
#include <windows.h>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
    int ok = 0;
    int n = 50;
    for (int i = 1; i <= n; ++i)
    {
        system("make.exe > make.txt");
        system("std.exe < make.txt > std.txt");
        double begin = clock();
        system("baoli.exe < make.txt > baoli.txt");
        double end = clock();

        double t = (end - begin);
        if (system("fc std.txt baoli.txt"))
        {
            printf("测试点#%d Wrong Answer\n", i);
        }
        else if (t > 1000) //1秒
        {
            printf("测试点#%d Time Limited Exceeded 用时 %.0lfms\n", i, t);
        }
        else
        {
            printf("测试点#%d Accepted 用时%.0lfms\n", i, t);
            ok++; //AC数量+1
        }
    }
    printf("\n");
    double res = 100.0 * ok / n;
    printf("共 %d 组测试数据,AC数据 %d 组。 得分%.1lf。", n, ok, res);

    Sleep(1000); //休眠1秒,为了节约对拍次数。
}

​上面造了50个测试点,我们还可以计算程序 AC 多少个点来评个总分。这样可以让我们大致地了解一下编出的程序的正确性。c++对拍,c++,算法,图论

 

c++对拍,c++,算法,图论

​ 这样子,对拍的作用就发挥到了极致。

原文链接

C++ 对拍详解 -QT开发中文网C++ 对拍详解 https://qt.0voice.com/?id=808文章来源地址https://www.toymoban.com/news/detail-722163.html

到了这里,关于C++ 对拍详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法——弗洛伊德算法(Floyd-Warshall)(图论)(c++)

    (蒟蒻的第四篇文章,希望dalao勿喷) (希望没问题) 声明: 1.本人变量定义的名称很low 2.本人用的方法也很low 3.但我觉得文章应该不low  (盲目自信) 第四篇文章讲讲Floyd算法 Floyd算法是一种寻找最短路径的常见算法,其特点是: 短,好理解(虽然其他算法也挺好理解的

    2023年04月09日
    浏览(25)
  • 【C++算法模板】图论-拓扑排序,超详细注释带例题

    推荐视频链接:D01 拓扑排序 给定一张 有向无环图 ,排出所有顶点的一个序列 A A A 满足:对于图中的每条有向边 ( x , y ) (x,y) ( x , y ) , x x x 在 A A A 中都出现在 y y y 之前,则称 A A A 是该图的顶点的一个拓扑序 拓扑排序 可以判断有向图中是否有环,可以生成拓扑序列 对于下

    2024年04月15日
    浏览(32)
  • 浅谈图论——迪杰斯特拉算法(leetcode例题,C++演示)

    如果你想问这个世界上什么算法是最牛逼的?博主是回答不上来的。但是,如果你问博主 什么数据结构是最牛逼 ?博主个人认为 图是最牛逼的数据结构 。因为很多的问题,都可以用图这种数据结构来表示。链表、树这种数据结构博主认为可以看成一种 特殊的图 。所以,博

    2024年02月20日
    浏览(74)
  • 【图论C++】Floyd算法(多源最短路径长 及 完整路径)

    UpData Log👆 2023.9.29 更新进行中 Statement0🥇 一起进步 Statement1💯 有些描述可能不够标准,但能达其意 常见的有: DJ算法 、 Floyd算法 、 A*算法 、 Bellman-Ford 算法 、 SPFA算法 其中 A*算法 是 DJ算法 的plus版, SPFA算法 是 Bellman-Ford 算法 的plus版 算法名称 DJ算法 Floyd算法 SPFA算法

    2024年02月19日
    浏览(33)
  • 【图论】【割点】【C++算法】928. 尽量减少恶意软件的传播 II

    视频算法专题 图论 割点 给定一个由 n 个节点组成的网络,用 n x n 个邻接矩阵 graph 表示。在节点网络中,只有当 graph[i][j] = 1 时,节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,

    2024年04月08日
    浏览(68)
  • C++排序算法:归并排序详解

    一、归并排序 二、基本算法         1、分离         2、合并         3、图片讲解 三、代码实现         1、分离函数         2、合并函数          3、完整代码          4、样例 四、总结          归并排序 (Merge Sort)是建立在归并操作上的一种既有效又稳

    2024年02月12日
    浏览(33)
  • C++ 离散化 算法 (详解)+ 例题

    1、性质 把 无限空间 中有限的个体映射到 有限的空间 中去,以此提高算法的空间效率。通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的压缩。 适用范围: 数的跨度很大,用的数很稀疏 例如:值域:1~10^9, 个数:10^5,值域很大,但是用到个数相对

    2024年02月19日
    浏览(35)
  • c++—0/1背包问题--贪心算法(详解)

    贪心算法的基本思想 •贪心算法的特点是每个阶段所作的选择都是局部最优的,它期望通过所作的局部最优选择产生出一个全局最优解。 贪心与动态规划: 与动态规划不同的是,贪心是 鼠目寸光 ; 动态规划是 统揽全局 。 贪心:每个阶段产生的都是局部最优解 贪心算法的

    2024年02月04日
    浏览(35)
  • c++ 算法之动态规划—— dp 详解

    dp 是 c++ 之中一个简单而重要的算法,每一个 OIer 必备的基础算法,你知道它究竟是什么吗? 目录 一、简介         1.为什么不能贪心?         2.揭秘 dp   二、应用         1.定义         2.边界值         3.动态转移方程         4.结果         5.代码

    2024年04月09日
    浏览(40)
  • 【JobScheduling】C++调度算法详解与实现

    作业调度是操作系统中一个关键的概念,它涉及到有效地分配和管理计算资源以执行任务。 作业调度算法在这一过程中起到关键作用,影响系统的性能和响应时间。 本篇博客旨在深入了解三种常见的作业调度算法以及C++实现: 先来先服务算法(FCFS) 、 短作业优先算法(

    2024年02月01日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包