对拍(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. SQL 给某字段添加汉字却显示??

    错误展示: 解决方案: 1.在要修改的数据库上单击鼠标右键,并选择“属性”.   2.在弹出的数据库属性窗口中点击“选择页”中的“选项”.   3.将排序规则由默认的SQL_Latin1_Genera ...

  2. C++语法小记---类型转换

    类型转换 C++类型转换主要包含两种: 隐式类型转换 小类型向大类型转换 char -> int short ->int int -> unsigned int int -> ...

  3. Django安装与简单配置(1)

    目录 1. 环境准备 2. 开始安装 2.1 安装Django 2.2 安装 Mysql数据库 3. 开始配置 3.1 Django简单配置 3.1.1 创建一个工程(project)为devops: ...

  4. Linux平台下SSD的TRIM指令的最佳使用方式(不区别对待NVMe)

    SSD写数据会出现什么问题 SSD读写的单位不是位,而是一个块.如果要改变这个块中的一位,首先要将整个块擦写成1,然后再写入更新的数据. 为了解决擦写块的低效,SSD的策略是将需要改写的块,读取出来, ...

  5. WEB前端常见受攻击方式及解决办法

    一个网站建立以后,如果不注意安全方面的问题,很容易被人攻击,下面就讨论一下几种漏洞情况和防止攻击的办法. 一.SQL注入 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的 ...

  6. 多个activity的博客参考,用mainactivity 调用 明天阅读一下

    https://blog.csdn.net/hbwxy521/article/details/53101019

  7. laravel 安装语言包

    一.composer依赖网站地址:https://packagist.org/ 二.在搜索框输入: laravel-lang 三.点击进入,根据自己的版本进行安装: composer require ...

  8. Markdown简洁语法说明

    学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.前言 ...

  9. PHP pclose() 函数

    定义和用法 pclose() 函数关闭由 popen() 打开的进程. 如果失败,该函数返回 FALSE. 语法 pclose(pipe) 参数 描述 pipe 必需.规定由 popen() 打开的进 ...

  10. [草稿]基于 Virtuoso 环境比较便捷的项目文件及权限管理方案

    https://www.cnblogs.com/yeungchie/ 假设如下情况: 1 项目名称 Project_01 2 包含 4 名研发用户,user01 和 user02 为前端工程师,use ...