对拍(C++)

对拍是什么

​ 众所周知,当我们正在考试敲代码的时候,每一道题,都会有某种正解能拿到满分;当我们想不出正解时,我们往往可以打暴力代码来骗分。

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

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

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


对拍的实现

1.准备基本代码

​ 首先,我们要有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 res=0;
int i;
for(i=1;i<=a;i++)
res++;
for(i=1;i<=b;i++)
res++;
printf("%d\n",res);
return 0;
}

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

2.制作数据生成器

​ 我们制作的数据要求格式和上面两份代码的输入格式一样。根据上面,我们可以知道输入的数据为2个数,中间有空格分隔。那么,我们的数据生成器就要输出2个数,中间也要用空格分隔。

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

​ 运行一下,果然生成了2个随机数。

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

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

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

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

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

​ 举几个简单的例子。

  1. a=rand()%2 时,a 的范围:\(0 \leq a \leq 1\) 。

  2. a=rand()%2+1 时,a 的范围:\(1 \leq a \leq 2\) 。

  3. 要想让 \(1 \leq a \leq 30000\) ,则 a=rand()%30000+1

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

    比如让 \(1 \leq a \leq 1,000,000\)

    int main()
    {
    srand(time(0));
    while(1)
    {
    int a=rand()%1000+1;
    int b=rand()%990+1;
    // a的最大值 × b的最大值=990000
    int c=rand()%10000+1;
    //a*b+c 刚好凑个1000000
    int d=a*b+c;
    cout<<d<<endl;
    }
    }

    看一下输出结果

    怎么样,是不是很神奇呢(滑稽)

3.对拍代码

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

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

4.运行对拍程序

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

​ 并且打开每一份代码,让每一份代码都生成一个同名的 .exe 程序。如下:

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

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

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

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

插入图片7

​ 这是存在差异的情况。

5.程序的美化

​ 众所周知,每一道编写程序题都有时间限制。那么我们可以用一个计时函数,来计算我们写的正解用的时间,判断它是否超时,并把所用时间在对拍程序上体现出来。

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

#include<iostream>
#include<cstdio>
#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 Enough 用时 %.0lfms\n",i,t);
}
else
{
printf("测试点#%d Accepted 用时%.0lfms\n",i,t);
ok++; //AC数量+1
}
}
cout<<endl;
double res=100.0*ok/n;
printf("共 %d 组测试数据,AC数据 %d 组。 得分%.1lf。",n,ok,res);
}

​ 上面造了50个测试点,我们还可以看看程序 AC 多少个点来评个总分。(当然这只是起一些美化作用,让对拍看起来更舒服)

​ 这样子,是不是感觉很有意思呢(滑稽*2)


总结

​ 经过上面的一番讲解,大家一定对“对拍”已经有了一些了解。相信大家跟着上面的步骤,也能用对拍来解决一些实际的问题。

​ 在考场上,对于一些 比较容易写出暴力代码 而 写正解又担心自己写不对 的情况,我们可以用自己的暴力代码和写的正解比较一下。(毕竟暴力代码肯定不会WA掉,输出的答案只是慢了些,但答案肯定不会错) 这么比较,就知道自己写的正解是不是对的了。

​ 而且,对拍还能方便地计算出任意随机数据所跑的时间,我们可以知道这个程序大约用的时间,我们可以自己再去调试优化。这避免了我们考试时写完代码,但是不知道自己的程序跑大数据非常慢,考试结束交程序评测的时候全是TLE。(悲)

​ 总之,对拍是个比较实用的工具,考试必备神器,一定要掌握它。

希望大家在2020NOIP中发挥超常,RP++!

EdisonBa

2020.8.15

对拍(C++)的更多相关文章

  1. 相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了!

    相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了! 先说图片X×dpi=点数dotX是图片实际尺寸,简单点,我们只算图片的高吧,比如说拍了张图片14 ...

  2. [OC笔记]@property之个人理解,大神轻拍

    /** * 一个简单的对象 * * @author suzhen * */ public class SimpleObjcet { /** * 声明一个age字段 */ private Object ...

  3. 完美实现类似QQ的自拍头像、上传头像功能!(Demo 源码)

    现在很多下载客户端程序都需要设定自己头像的功能,而设定头像一般有两种方式:使用摄像头自拍头像,或者选择一个图片的某部分区域作为自己的头像. 一.相关技术 若要实现上述的自拍头像和上传头像的功能,会碰到 ...

  4. 可在广域网部署运行的QQ高仿版 -- GG叽叽V3.5,增加自拍头像功能、细节优化(源码)

    距离上次发版本(GG叽叽V3.4,增加系统设置.最近联系人.群功能)又有1个月了,在这个月内,由于空闲时间不是很多,所以,GG增加的主要功能只是拍照并设定其为自己头像.修改密码.删除好友.以及一些bu ...

  5. 高拍仪拍照SDK开发(良田影像S300L|S500L)

    高拍仪拍照SDK开发下载地址:点击下载 本SDK适用于:良田影像S300L|S500L 高拍仪如图: SDN开发包安装之后找到安装目录,如图: 大家找到各自需要的版本即可,需要注意的是如果需要上传图片 ...

  6. ajax异步上传到又拍云的实例教程

    作者:白狼 出处:www.manks.top/article/async_upload_to_upyun 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否 ...

  7. ACM程序对拍

    有时候在OJ刷题目的时候,总是会遇到不知名bug,题目总不能AC,自己测试的一些数据又都能得出正确的结果,又或是直接暴力会TLE,改了算法,但是仍然WA,这时候进行程序对拍测试数据不失为一个好办法.程 ...

  8. 我的Linux对拍脚本

    本文用于Linux下bash的对拍脚本: brute为本目录的暴力程序.. pro为优化过的程序 mak造数据的.. #!/bin/bash while(true)do ./mak printf &q ...

  9. OPPO某某產品拍攝範圍嶄露頭角

    手機熱風暴再次襲來.oppo 開闢新道路.OPPO爆料N3採用旋智能轉攝像頭!很青睞一些愛拍照的我們.愛攝影的我們.覺的代攝影機麻煩.OPPo同樣給你全新的視野新加坡自由行. 隨著OPPO N3發布會 ...

  10. 趣拍SDK接入问题Android

    Android接入趣拍问题. 大部分android开发者第一次下载SDK后,特别是导入到eclipse后,可以运行工程,但点击app中的record没反映,每次点击record按钮 会出现如下log. ...

随机推荐

  1. 设计模式:singleton模式

    目的:限制类的实例个数只能是一个 例子: #define AGT_DECLARE_SINGLETON(ClassName) \ public: \ static ClassName *Instance ...

  2. Makefile中的奇葩字符

    % : Makefile规则通配符,一般出现在目标或是依赖中 * : shell命令中的通配符,一般出现在命令中 $@:目标的名字 $^:所有依赖的名字 $<:第一个依赖的名字 $?:所有依赖中 ...

  3. flask json 格式下 decimal 不是正确格式的问题

    import decimal class DecimalEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, decima ...

  4. Vue、Nuxt服务端渲染,NodeJS全栈项目,面试小白的博客系统~~

    Holle,大家好,我是李白!! 一时兴起的开源项目,到这儿就告一段落了. 这是一个入门全栈之路的小项目,从设计.前端.后端.服务端,一路狂飙的学习,发量正在欣喜若狂~~ 接触过WordPress,H ...

  5. NGINX 上的限流

    NGINX 上的限流(译) zlup YP小站  今天 前言 本文是对Rate Limiting with NGINX and NGINX Plus的主要内容(去掉了关于NGINX Plus相关内容) ...

  6. Java后端总结

    Java后端开发学习路线 编程基础 Java语言 语言基础 基础语法 面向对象 接口 容器 异常 泛型 反射 注解 I/O 图形化(如Swing) JVM 类加载机制 字节码执行机制 jvm内存模型 ...

  7. UDP 绑定信息

    """ 建立->绑定本地ip地址和端口号->接收数据->转码输出->关闭客户端 """ from socket im ...

  8. CF R 635 div1 C Kaavi and Magic Spell 区间dp

    LINK:Kaavi and Magic Spell 一打CF才知道自己原来这么菜 这题完全没想到. 可以发现 如果dp f[i][j]表示前i个字符匹配T的前j个字符的方案数 此时转移变得异常麻烦 ...

  9. NameNode中的高可用方案

    NN中元数据的可靠性是可以保证的,但是其可用性并不高,因为Namenode是单节点的,所以一旦这个节点不能工作,那么整个hdfs都不能工作,但是由于SecondaryNameNode的机制,所以,即便 ...

  10. 【Canal】互联网背景下有哪些数据同步需求和解决方案?看完我知道了!!

    写在前面 在当今互联网行业,尤其是现在分布式.微服务开发环境下,为了提高搜索效率,以及搜索的精准度,会大量使用Redis.Memcached等NoSQL数据库,也会使用大量的Solr.Elastics ...