• 随机数据生成与对拍【c++版,良心讲解】


    10.7更新:见最下面

    离NOIP2018没剩多长时间了,我突然发现我连对拍还不会,于是赶紧到网上找资料,找了半天发现了一个特别妙的程序,用c++写的!

     

    不过先讲讲随机数据生成吧。

    很简单,就是写一个程序模拟输入数据,然后利用rand()编写随机数。

    在头文件cstdlib中,有rand(), srand()函数,以及常量RAND_MAX.

    RAND_MAX在windos系统中为 0x7fff = 2^15-1 = 32767;在Unix(可以理解为linux,只不过linux是unix一种,是”类unix“)下为 2^31-1 = 2147483647(都是32位),加上一个正数最高位就为1,就变成了负数,即 -RAND_MAX = RAND_MAX + 1,所以 - rand() / RAND_MAX = rand() / (RAND_MAX + 1)。

    rand()返回一个在0~RAND_MAX之间的整数。

    srand(seed)函数接受一个unsigned int类型的参数seed,以seed为“随机种子”。

    rand()函数基于线性同余递推式(就是某种递推式吧~)生成随机数,“随机种子“相当于这个递推式的初始参数,若不执行srand(),则种子默认为1.

    当种子确定后,生成的随机数列也是固定的,因此这种随机方法是”伪随机“,所以一般要在开始调用srand(),且以当前时间为随机种子。

    怎么写呢?ctime里有一个tim函数,调用time(0)可以返回从1970年1月1日0时0分0秒(Unix纪元)到现在的秒数。然后写这么一句就行了:srand((unsigned)time(0));

     

    接下来才是重点:对拍~~

    对拍是啥我就不多说了,直接讲怎么写。

    首先,得有这么几个程序:

    1.随机数据生成程序random.cpp.

    2.自己的美妙算法程序sol.cpp

    3.暴力程序bf.cpp (bf:brute force 暴力)

    然后我们要写一个脚本,循环执行以下过程:

    1.运行random.exe.

    2.运行sol.exe

    3.运行bf.exe

    4.比对sol.out和bf.out的内容是否一致。

    虽然Windos和类unix分别有bat批处理脚本和bash脚本,然而因为我太懒不想学别的语言,就废了半天功夫找到了一个用c++写的(你这道勤快)。

    还是在cstdlib中,有一个system函数,他接受一个字符串作为参数,然后把这个字符串作为系统命令执行,栗如:system("C:\Users\Administrator\Desktop\random.exe"),执行windos桌面上的random.exe。

    比对的话,windows用fc,类Unix用diff,他们接受两个文件路径,比较二者是否一致,若一致返回0,否则返回非0值。

    下面放出windos的对拍程序,程序都是在桌面上的

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 #include<ctime>
    12 using namespace std;
    13 #define enter puts("") 
    14 #define space putchar(' ')
    15 #define Mem(a) memset(a, 0, sizeof(a))
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const int eps = 1e-8;
    20 //const int maxn = ;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 
    37 int main()
    38 {
    39     for(int t = 1; t <= 100; ++t)
    40     {
    41         system("C:\Users\Administrator\Desktop\random.exe");
    42         db Beg = clock();            //记录sol.exe的运行时间 
    43         system("C:\Users\Administrator\Desktop\sol.exe");
    44         db End = clock();
    45         system("C:\Users\Administrator\Desktop\bf.exe");
    46         if(system("fc C:\Users\Administrator\Desktop\sol.out C:\Users\Administrator\Desktop\bf.out"))
    47         {
    48             puts("WA"); return 0;
    49         }
    50         else printf("AC, #%d, Time : %.0lfms
    ", t, End - Beg);
    51     }
    52     return 0;
    53 }
    View Code

    类unix上的对拍程序,只需要更改上面的代码system中的路径格式,把fc改成diff,用时单位该为”秒“(windos是毫秒)。

    于是我又写了一个linux下的,奇特的是,双斜杠单斜杠竟然都行,而且时间还是以毫秒为单位……

     1 #include<cstdio>
     2 #include<ctime>
     3 #include<cstdlib>
     4 using namespace std;
     5 typedef double db;
     6 
     7 int main()
     8 {
     9   for(int i = 1; i <= 10000; ++i)
    10     {
    11       system("//home//noilinux//Desktop//random");
    12       db Beg = clock();
    13       system("//home//noilinux//Desktop//sol");
    14       db End = clock();
    15       system("//home//noilinux//Desktop//bf");
    16       if(system("diff //home//noilinux//Desktop//sol.out //home/noilinux//Desktop//bf.out"))
    17       {
    18       puts("WA"); return 0;
    19       }
    20       else printf("AC #%d, Time : %.0lfms
    ", i, End - Beg);
    21     }
    22   return 0;
    23 }
    View Code

     

    这里给一个a + b的对拍程序:

    首先是random.cpp

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 #include<ctime>
    12 using namespace std;
    13 #define enter puts("") 
    14 #define space putchar(' ')
    15 #define Mem(a) memset(a, 0, sizeof(a))
    16 typedef long long ll;
    17 typedef double db;
    18 const int INF = 0x3f3f3f3f;
    19 const int eps = 1e-8;
    20 //const int maxn = ;
    21 inline ll read()
    22 {
    23     ll ans = 0;
    24     char ch = getchar(), last = ' ';
    25     while(!isdigit(ch)) {last = ch; ch = getchar();}
    26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    27     if(last == '-') ans = -ans;
    28     return ans;
    29 }
    30 inline void write(ll x)
    31 {
    32     if(x < 0) x = -x, putchar('-');
    33     if(x >= 10) write(x / 10);
    34     putchar(x % 10 + '0');
    35 }
    36 
    37 int main()
    38 {
    39     freopen("random.in", "w", stdout);
    40     srand((unsigned)time(0));
    41     write(rand() % rand()); space; write(rand() % rand());
    42     return 0;
    43 }
    View Code

    然后是sol.cpp(随便拷的一份LCT的……巨啊)

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cstring>
      5 using namespace std;
      6 struct node 
      7 {
      8     int data,rev,sum;
      9     node *son[2],*pre;
     10     bool judge();
     11     bool isroot();
     12     void pushdown();
     13     void update();
     14     void setson(node *child,int lr);
     15 }lct[233];
     16 int top,a,b;
     17 node *getnew(int x)
     18 {
     19     node *now=lct+ ++top;
     20     now->data=x;
     21     now->pre=now->son[1]=now->son[0]=lct;
     22     now->sum=0;
     23     now->rev=0;
     24     return now;
     25 }
     26 bool node::judge(){return pre->son[1]==this;}
     27 bool node::isroot()
     28 {
     29     if(pre==lct)return true;
     30     return !(pre->son[1]==this||pre->son[0]==this);
     31 }
     32 void node::pushdown()
     33 {
     34     if(this==lct||!rev)return;
     35     swap(son[0],son[1]);
     36     son[0]->rev^=1;
     37     son[1]->rev^=1;
     38     rev=0;
     39 }
     40 void node::update(){sum=son[1]->sum+son[0]->sum+data;}
     41 void node::setson(node *child,int lr)
     42 {
     43     this->pushdown();
     44     child->pre=this;
     45     son[lr]=child;
     46     this->update();
     47 }
     48 void rotate(node *now)
     49 {
     50     node *father=now->pre,*grandfa=father->pre;
     51     if(!father->isroot()) grandfa->pushdown();
     52     father->pushdown();now->pushdown();
     53     int lr=now->judge();
     54     father->setson(now->son[lr^1],lr);
     55     if(father->isroot()) now->pre=grandfa;
     56     else grandfa->setson(now,father->judge());
     57     now->setson(father,lr^1);
     58     father->update();now->update();
     59     if(grandfa!=lct) grandfa->update();
     60 }
     61 void splay(node *now)
     62 {
     63     if(now->isroot())return;
     64     for(;!now->isroot();rotate(now))
     65     if(!now->pre->isroot())
     66     now->judge()==now->pre->judge()?rotate(now->pre):rotate(now);
     67 }
     68 node *access(node *now)
     69 {
     70     node *last=lct;
     71     for(;now!=lct;last=now,now=now->pre)
     72     {
     73         splay(now);
     74         now->setson(last,1);
     75     }
     76     return last;
     77 }
     78 void changeroot(node *now)
     79 {
     80     access(now)->rev^=1;
     81     splay(now);
     82 }
     83 void connect(node *x,node *y)
     84 {
     85     changeroot(x);
     86     x->pre=y;
     87     access(x);
     88 }
     89 void cut(node *x,node *y)
     90 {
     91     changeroot(x);
     92     access(y);
     93     splay(x);
     94     x->pushdown();
     95     x->son[1]=y->pre=lct;
     96     x->update();
     97 }
     98 int query(node *x,node *y)
     99 {
    100     changeroot(x);
    101     node *now=access(y);
    102     return now->sum;
    103 }
    104 int main()
    105 {
    106     freopen("random.in", "r", stdin);
    107     freopen("sol.out", "w", stdout);
    108     scanf("%d%d",&a,&b);
    109     node *A=getnew(a);
    110     node *B=getnew(b);
    111     //连边 Link
    112         connect(A,B);
    113     //断边 Cut
    114         cut(A,B);
    115     //再连边orz Link again
    116         connect(A,B);
    117     printf("%d
    ",query(A,B)); 
    118     return 0;
    119 }
    View Code

    最后是bf.cpp

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<cctype>
     8 #include<vector>
     9 #include<stack>
    10 #include<queue>
    11 using namespace std;
    12 #define enter puts("") 
    13 #define space putchar(' ')
    14 #define Mem(a) memset(a, 0, sizeof(a))
    15 typedef long long ll;
    16 typedef double db;
    17 const int INF = 0x3f3f3f3f;
    18 const int eps = 1e-8;
    19 //const int maxn = ;
    20 inline ll read()
    21 {
    22     ll ans = 0;
    23     char ch = getchar(), last = ' ';
    24     while(!isdigit(ch)) {last = ch; ch = getchar();}
    25     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
    26     if(last == '-') ans = -ans;
    27     return ans;
    28 }
    29 inline void write(ll x)
    30 {
    31     if(x < 0) x = -x, putchar('-');
    32     if(x >= 10) write(x / 10);
    33     putchar(x % 10 + '0');
    34 }
    35 
    36 int main()
    37 {
    38     freopen("random.in", "r", stdin);
    39     freopen("bf.out", "w", stdout);
    40     int a = read(), b = read();
    41     write(a + b); enter;
    42 }
    View Code

    把三个程序分别运行一下,得到三个exe。然后运行上面的对拍程序就行啦~~

    附一下效果

     如果把bf改成write(a +b + 1)的话:

    这时候出错的数据就是当前的random.in了~~

    ***10月7日更新***

    小云彩(tql)告诉我了一个更简便的写法。

    在调用system的时候,里面可以不用写的那么复杂。如果这些东西在同一目录下,我们只用这么写:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<ctime>
     4 typedef double db;
     5 using namespace std;
     6 
     7 int main()
     8 {
     9     for(int t = 1; t <= 1000; ++t)
    10     {
    11         system(".\random.exe");
    12         db Beg = clock();
    13         system(".\ac.exe");
    14         db End = clock();
    15         system(".\bf.exe");
    16         if(system("fc .\ac.out .\bf.out"))
    17         {
    18             printf("WA
    "); return 0;
    19         }
    20         else printf("#%d AC %.2lfms
    ", t, End - Beg);
    21     }
    22     return 0;
    23 }
    View Code

    windos下用 .//,linux下是 ~\。

    方便。

    对拍讲完啦~~~祝各位继续AKIOI~~

  • 相关阅读:
    HttpSession
    查看端口被哪个进程占用了
    变体类型 Variant VARIANT
    BDE View not exists
    c++builder 解压缩
    nginx的allow和deny配置
    linux下如何启动nginx?
    java如何发起一次http的post请求?
    mysql如何用sql添加字段如何设置字符集和排序规则
    设置Tomcat的UTF-8编码
  • 原文地址:https://www.cnblogs.com/mrclr/p/9544749.html
Copyright © 2020-2023  润新知