对拍的正确打开方式

导览:对拍的原因,数据生成器模板,对拍模板。

前置知识:C++基础。

咱使用的系统是 Windows 10。


对拍的原因

在比赛时,往往不能保证自己写的一些优化的正确性,这时可以额外写一份一定正确的暴力做法,然后随机生成数据,比较两者输出的异同。这便是对拍。

在调试时,如果实在不知道什么数据会出错,也可以取一份标程,进行对拍。

数据生成器模板

// gen.cpp

#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <ctime>

// 或者可以用万能头,写得方便些
// #include <bits/stdc++.h>

inline int random(int a, int b) {
  return a + rand() % (b - a + 1);
}

// define 玩家也可以这样写
// #define random(a,b) ((a) + rand() % ((b) - (a) + 1))

stringstream ss;
int main(int argc, char *argv[]) {
  int seed;
  if (argc > 1) {
    ss.clear();
    ss << argv[1];
    ss >> seed;
  } else {
    seed = time(NULL));
  }
  srand(seed);
  
  // ...
  
  return 0;
}

要点

  1. 若在对拍程序中,没为gen.exe传入main函数的参数,那么只会每秒更新一次rand函数的种子,一秒内会重复相同数据的生成。
  2. argc为参数个数,argv[]存储各个参数(各参数为char*类型)。因为argv[0]为程序名,所以argv[1]才是我们在对拍程序中传入的随机数。

对拍模板

新建一个duipai.bat文件,填入以下内容:

@echo off
:loop
  gen %random% >gen.out
  sol <gen.out >sol.out
  std <gen.out >std.out
  fc sol.out std.out
  if errorlevel 1 pause
goto loop

要点

  1. @echo off用于关闭回显,这样批处理程序运行时便不会显示执行的命令。
  2. 运行到第8行,会跳回第2行,这里的标记名可以自定义,咱用的是loop
  3. 传入%random%作为数据生成器gen.exemain函数的参数(取 [0, 65535] 内的随机整数),也可以去掉(如上文所述,效率会降低)。并将结果输出至gen.out
  4. gen.out作为输入,分别将解答程序sol.exe和标准程序std.exe的结果输出至sol.outstd.out
  5. fc用以比较两个文件的差异,有则暂停,无则循环。为啥咱想到了音游里的”Full Combo”?(大雾)

当然,也可以用C++写:

#include <cstdio>
#include <cstdlib>

int main() {
  int T = 0;
  while (true) {
    printf("Test Case %d: \n", ++T);
    system("gen %random% >gen.out");
    system("sol <gen.out >sol.out");
    system("std <gen.out >std.out");
    if (system("fc sol.out std.out")) {
      puts("WA");
      system("pause");
    } else {
      puts("AC");
    }
    puts("====================");
  }
  return 0;
}

不过不知为何,在开始对拍前会迟钝一段时间,还是用批处理轻量高效。

尾声

有空学一下 CYaRon 的用法。

下次顺便写一些特殊数据的生成套路。

明天早起散步。

点赞

Leave a Reply