对拍(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. Windows搭建Redis集群-详细教程

    一.集群知识 1.集群的概念 所谓的集群,就是通过添加服务器的数量,提供相同的服务,从而让服务器达到一个稳定.高效的状态. 2.使用redis集群的必要性 问题:我们已经部署好了redis,并且能启动 ...

  2. 汇总我在IDEA中使用Maven导包遇到的问题

    看吐了吗?我是真吐了 真正遇到这些问题的朋友看到这,是不是有种找到知音的感觉,别怕,你不是在一个人战斗,苦逼的日子里,还有个我陪你一起苦逼,吐了吐了,这问题不知道耗费了我多久的时间,百度好多也解决不了 ...

  3. 性能1.84倍于Ceph!网易数帆Curve分布式存储开源

    在上周刚结束的网易数字+大会上 网易数帆宣布: 开源一款名为Curve的高性能分布式存储系统, 性能可达Ceph的1.84倍! 网易副总裁.网易杭州研究院执行院长兼网易数帆总经理汪源: 基础软件的能力 ...

  4. 什么是CSV

    逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本).纯文本意味着该文件是一个字符序列,不 ...

  5. springboot(三)SpringDataJPA完成CRUD

    参考博客—恒宇少年:https://www.jianshu.com/p/b6932740f3c0 纯洁的微笑:http://www.ityouknow.com/springboot/2016/08/2 ...

  6. OpenLDAP on Centos7

    一.环境准备 echo nameserver 114.114.114.114 > /etc/resolv.conf ##更改DNSecho 192.168.0.190 hello.com > ...

  7. Numpy数组的函数

    import numpy as np # 将 0~100 10等分 x = np.arange(0,100,10) # array([ 0, 10, 20, 30, 40, 50, 60, 70, 8 ...

  8. PHP printf() 函数

    实例 输出格式化的字符串: <?php高佣联盟 www.cgewang.com$number = 9;$str = "Beijing";printf("There ...

  9. PHP mysqli_real_escape_string() 函数

    转义字符串中的特殊字符: <?php 高佣联盟 www.cgewang.com // 假定数据库用户名:root,密码:123456,数据库:RUNOOB $con=mysqli_connect ...

  10. luogu P6570 [NOI Online #3 提高组]优秀子序列 二进制 dp

    LINK:P6570 [NOI Online #3 提高组]优秀子序列 Online 2的T3 容易很多 不过出于某种原因(时间不太够 浪了 导致我连暴力的正解都没写. 容易想到 f[i][j]表示前 ...