随机数据生成与对拍

# 随机数据生成与对拍

引言

在漫长的\(OI\)生涯中,你肯定遇到过这些情况

  • 在OI赛制下,你写了一份你自认为是正解的代码,但是你不确定自己是否考虑到了所有的细节,你不敢轻易提交
  • 对于有些无法获得数据的题目,你不知道自己错在了哪里
  • 对于能够获得数据的题目,你拿到的数据都是上万级别的数据,难以\(Debug\).

这时候,我们就可以试试随机数据生成与对拍`


  • 什么是随机数据生成?

顾名思义,就是针对我们的需求生成随机的数据。比如生成随机的整数序列,生成随机的树,生成随机的图。

  • 什么是对拍?

对拍说白了就是对答案,举个栗子:在文化课中,对于同一道填空题,我们在写出自己的答案后,可能会找其他同学对一下答案,看是不是一样的。放在\(OI\)中,就是对于同一道题目,两个不同的人写了两份不同的程序,再针对同一组数据,看看两份程序的输出结果是否一样。

  • 随机数据生成和对拍有什么用呢?

比方说在无法获得实时评测反馈的比赛中(\(NOIp\)),对于一道题目,你思考并实现了一个“高分解法”,但不能确保这个程序是否完全正确,这种情况下,就可以考虑编写一份随机数据生成程序,一份用正确但是会\(TLE\)的暴力算法写的程序,然后将两个程序对拍,看是否输出结果一致。

要是暴力都不会打,那就输出随机数据骗分吧

  • 那么如何实现随机数据生成呢?

参考《算法竞赛进阶指南》P439

先给出随机数据生成的模板,适用于此文中所有的生成数据方法

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int random(int n)//生成一个[0,n-1]范围内的数
{
    return (long long)rand()*rand()%n;
}
int main()
{
    freopen("data.in","w",stdout);
    //将生成的数据输出到名为data.in的文件中
    srand((unsigned)time(0));
    //具体内容...
    return 0;
}
  • 生成数据的方法:

    • 随机生成整数序列

      //随机生成n(n<=1e5)个绝对值在1e8之间的整数
      int n=random(100000)+1,x;
      for(int i=1;i<=n;i++)
          printf("%d ",random(x*2+1)-x);
      putcha('\n');//可有可无 
    • 随机生成排列
    //随机生成1~n(n<=1e5)的排列 
    
    //STL的方法
    int n=random(100000)+1,a[100050];
    for(int i=1;i<=n;i++)
        a[i]=i;
    random_shuffle(a+1,a+n+1);//库文件algorithm
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    
    //瞎搞方法
    int n=random(100000)+1,bool vis[100050];
    for(int i=1;i<=n;i++)
    {
        int x=random(n)+1;
        while(vis[x]==1)
            x=random(n)+1;
        vis[x]=1;printf("%d ",x);
    }
    • 随机生成若干个区间(常用于数据结构题目的区间操作)
    //随机生成m个[1,n]的子区间
    for(int i=1;i<=m;i++)
    {
        int l=random(n)+1;
        int r=random(n)+1;
        if(l>r) swap(l,r);
        printf("%d %d\n",l,r);
    }
    • 随机生成树
    //随机生成一棵n个点带边权(<=100000)的树
    for(int i=2;i<=n;i++)
    {
        int fa=random(i-1)+1;
        int val=random(100000)+1;
        printf("%d %d %d\n",fa,i,val);
     } 
    • 随机生成连通图
    //随机生成一张n个点,m条边的无向图.
    pair<int,int> e[];//[]内填写数组大小
    map<pair<int,int>,bool> h;//库文件map
    //先生成一棵树,保证联通
    
    int n=random(具体大小),m=random(具体大小);
    printf("%d %d\n",n,m);
    for(int i=1;i<n;i++)
    {
        int fa=random(i)+1;
        e[i]=make_pair(fa,i+1);
        h[e[i]]=h[make_pair(i+1,fa)]=1;
    }
    //在生成剩余的m-n+1条边
    for(int i=n;i<=n;i++)
    {
        int x,y;
        do{
            x=random(n)+1,y=random(n)+1;
        }while(x==y || h[make_pair(x,y)]);
        e[i]=make_pair(x,y);
        h[e[i]]=h[make_pair(y,x)]=1;
    }
    //随机打乱,输出
    random_shuffle(e+1,e+m+1);//库文件algorithm
    for(int i=1;i<=m;i++)
        printf("%d %d\n",e[i].first,e[i].second); 
    • 随机生成链
    //生成一条有n个节点的链
    int n=random(1000)+1;printf("%d\n",&n);
    int root=random(n)+1;bool vis[100000];
    vis[root]=1;int last=root;
    for(int i=1;i<n;i++)
    {
        int x=random(n)+1;
        while(vis[x]==1) x=random(n)+1;
        printf("%d %d\n",last,x);
        last=x;vis[x]=1;
    }
    • 随机生成一张菊花图
    //生成一条有n个节点的菊花图
    int n=random(1000)+1;printf("%d\n",n);
    int root=random(n)+1;
    for(int i=1;i<=n;i++)
    {
        if(i==root) continue;
        printf("%d %d\n",root,i);
    }

  • 那么如何实现对拍呢?

假设此时我们已经编写好了三个程序:

  1. 自己编写的“高分解法”程序,名为“sol.cpp”,改程序输出答案到data.out中。
  2. 自己编写的“暴力解法”程序,名为“bf.cpp”,该程序输出正确答案到data.ans中。
  3. 自己编写的随机数据生成程序,名为“random.cpp”,该程序输出随机数据到data.in中

依次编译这三个程序,得到三个exe文件,然后运行如下程序即可。

#include <cstdlib>
#include <iostream>
#include <cstdio>
#include <ctime>

using namespace std;
int main()
{
    for(int T=1;T<=100;T++)//T即为测试数据的组数
    {
        system("C:\\random.exe");//运行数据生成的程序

        // 获取正解程序的运行时间,Windows下单位为ms
        double st=clock();
        system("C:\\sol.exe");//运行正解程序
        double ed=clock();
        system("C:\\bf.exe");//运行暴力程序
        if(system("fc data.out data.ans"))
        //对比正解与暴力程序的输出结果,如果不同
        {
            puts("Wrong Answer");
            return 0;
        }
        else printf("Accepted, 测试点 #%d, 用时 %.0lfms\n",T,ed-st);
        //如果输出结果一样,那么输出程序运行时间
    }
    return 0;
}

举个栗子:

  • 情景:此时我手中有一份95分的代码,和一份\(std\),但是手中并没有WA了的那个点的数据
    95分代码:

    无法获得数据:
  • 这时候就可以利用std,随机数据生成与对拍来找出我这个95分程序的bug
  • 首先我们先把四个程序写好放在同一个文件夹

    其中bf是std,sol是我的95分程序,rand是针对这道题目写出来的随机数据生成器,对拍即上文提到的那个模板。
  • 接着我们编译运行前三个程序,得到3个exe类型的程序,及两个答案文件,一个输入文件
  • 然后我们编译运行那个名为对拍的程序就可以了,会出现如下结果
  • 我们可以看到,如果我们的sol程序的输出结果和bf的输出结果一样,那么它就会输出Accepted和我们这个col程序对于这一组数据的运行时间
  • 而要是有不同的地方,这个对拍程序就会指出在哪里出现差异,这时我们只要打开data.in这个文件开始思考自己程序的bug就行了

完结撒花
typed by zbwer 2019-08-31
部分代码引用李煜东的《算法竞赛进阶指南》

原文地址:https://www.cnblogs.com/fengzi8615/p/11699820.html

时间: 2024-08-12 00:14:57

随机数据生成与对拍的相关文章

机器学习算法的随机数据生成

在学习机器学习算法的过程中,我们经常需要数据来验证算法,调试参数.但是找到一组十分合适某种特定算法类型的数据样本却不那么容易.还好numpy, scikit-learn都提供了随机数据生成的功能,我们可以自己生成适合某一种模型的数据,用随机数据来做清洗,归一化,转换,然后选择模型与算法做拟合和预测.下面对scikit-learn和numpy生成数据样本的方法做一个总结. 1. numpy随机数据生成API numpy比较适合用来生产一些简单的抽样数据.API都在random类中,常见的API有:

d3 使用随机数据生成条形图

var dataset = d3.range(25).map(function(){ return d3.round(d3.random.normal(15,8)(),1); }) // 返回 [27.2, 12.9, 12.2, 6.8, 9.4, 7.1, 17.5, 30, 16.6, 24.3, 19, 16.6, 5.8, 6.1, 5, 32.3, 6.4, 17.5, 5.1, 19, 15.5, 22.4, 30.4, 6.2, 15.8] d3.range(25)  生成25个

对拍和随机数据生成

c++ 对拍 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<set> #include<vector> #include<cmath> #include<ctime> using namespace std; typedef long long ll

随机数据生成工具Mockaroo

原文地址:https://www.cnblogs.com/zwh1993/p/Mockaroo.html

.NET使用Bogus生成大量随机数据

.NET如何生成大量随机数据 在演示Demo.数据库脱敏.性能测试中,有时需要生成大量随机数据.Bogus就是.NET中优秀的高性能.合理.支持多语言的随机数据生成库. Bogus的Github链接:https://github.com/bchavez/Bogus,图标如下: 安装Bogus 目前Bogus最新版是28.0.2,本文演示基本该版本,不保证官方以后会不会修改本文的使用方式. 使用Powershell: PM> Install-Package Bogus -Version 28.0.

随机数据的生成

import numpy as np # (1)random(d0,d1,....dn)用来生成d0*d1*....*dn维的数组.数组的值在[0,1)之间 np.random.rand(3,2,2)#生成一个3*2*2的数组 array([[[0.10141273, 0.97087629], [0.57045156, 0.62780166]], [[0.15425975, 0.21828791], [0.03630166, 0.60174227]], [[0.20345412, 0.51719

irms模拟数据生成及数据分析

一.数据准备 1.每天生成随机一个文本,每小时向文本中追加2次数据,每次10万条 随机数据生成: 2,32  * * * *  bash /mnt/jediael/irms/signalGenerator/signalGenerator.sh >> /home/jediael/sg.log 2>&1 类:SignalGenerator 2.每天将前一天生成的数据文本导入HDFS 32 0 * * * bash /mnt/jediael/irms/signalGenerator/c

Python一个可以生成随机数据的库

发现一个十分有用的库 faker,作用竟是可以生成各种各样的随机数据 新版本要使用 pip install fake-factory 而不能直接 pip install fake git:https://github.com/joke2k/faker文档:http://fake-factory.readthedocs.io/en/master/index.html 文档十分清楚, 用法就是这样的了, #-*- coding:utf-8 -*- from faker import Factory

利用Java随机,生成随机学生数据

为模拟向数据库中大量插入学生数据(注:此处应该用PreparedStatement.batchUpdate等批处理提高效率)的情形,通过Java随机来生成学生数据. 一.要生成的学生数据 students表设计如下: 其中前三项是数据库自动生成的,后面的10项需要程序生成. >>基于实际要求,插入的Student数据中,major和jnshuId不能同时相同.但由于随机数的不确定性,在程序中限制两个Student的major和jnshuId不同时相同复杂而低效.因此,选择在数据库中将major