首页 > 其他分享 >浅谈对拍

浅谈对拍

时间:2024-04-02 16:11:06浏览次数:19  
标签:std pr 浅谈 tot cpp data string

在 OI 练习中,经常出现代码无法通过评测的情况。当我们无法获取测试数据或测试数据过大,不便于调试时,对拍便可以帮助快速找到问题所在。

注意
本文所述的对拍方法主要运用于 NOI Linux。Windows 系统在 rand 函数取值上界和批处理脚本的写法上可能存在差异。

生成随机数据

使用 rand 函数,可以生成一个在 \(0\) 到 RAND_MAX(取值因系统而异,NOI Linux 为 \(2147483647\)) 的数字。当需要 \(1\) 到 \(n\) 的数时,可以利用 \(i \bmod n \in [0,n-1]\) 的性质取模求解:

int my_rand(int n){
    return rand()%n+1;
}

这个函数使用一个种子(默认为 \(1\))利用公式计算得到。为了在每次对拍获得不同的数据,应当在每次使用前将种子重置。
重置为秒级种子:srand(time(0));
重置为毫秒级种子: std::chrono::system_clock::now().time_since_epoch().count()
为了方便调试,建议先生成些小数据。

准备

  • 一个随机数据生成器 rand.cpp
  • 自己的代码 my.cpp
  • 正解或暴力 std.cpp
  • 如果有 Special Judge,则需要一个 spj.cpp,提前编译好。

单线程对拍

逐个运行各个程序效率较低,我们使用批处理脚本,代码如下:

#!/bin/bash
while true ; do
	g++ rand.cpp -o rand > nul
	./rand > data.in
	g++ std.cpp -o std > nul
	./std < data.in > data.ans
	g++ my.cpp -o my > nul
	./my < data.in > data.out
	diff data.out data.ans
	if [ $? -ne 0 ] ; then break ; fi
done

其中 diff 可以实现两个文本的比对,如果没有出入,则不返回值,继续循环。
当我们有 Special Judge 时,一种方法是将结果输出到文件里,与 Accepted 时返回的信息进行比对,代码如下:

#!/bin/bash
while true ; do
	g++ rand.cpp -o rand > nul
	./rand > data.in
	g++ std.cpp -o std > nul
	./std < data.in > data.ans
	g++ my.cpp -o my > nul
	./my < data.in > data.out
	./spj > result
	diff result accepted
	if [ $? -ne 0 ] ; then break ; fi
done

多线程对拍

由于难度较大,不建议在竞赛中使用,这里给出一份代码。

多线程对拍
#include <bits/stdc++.h>
using namespace std;
void Black() { printf("\033[37m"); }
void Red() { printf("\033[31m"); }
void Green() { printf("\033[32m"); }
void Yellow() { printf("\033[33m"); }
void Blue() { printf("\033[34m"); }
void Purple() { printf("\033[35m"); }
void DeepGreen() { printf("\033[36m"); }
void White() { printf("\033[37m"); }
int sys(string cmd) { return system(cmd.c_str()); }
#define nnow steady_clock::now()
#define dc duration_cast<duration<double>>(t2 - t1)
#define time ut.count()
#define pc putchar
#define pr printf
#define ps puts
#define Wall ps("--------------------------------------------")
#define CE(x)  Re(), ps("Error"), Bl(), Wall, exit(1);
#define COM(x) Pu(), pr("Compile " #x " "), Bl();
#define WA()   Wh(), pr("%03d ", i), Re(), ps("Wrong Answer"), Bl(), exit(1);
#define Bls "\033[37m"
#define Res "\033[31m"
#define Grs "\033[32m"
#define Yes "\033[33m"
#define BLs "\033[34m"
#define Pus "\033[35m"
#define DGs "\033[36m"
void BLK() { pr("\033[30m"); }
void Bl() { pr("\033[37m"); }
void Re() { pr("\033[31m"); }
void Gr() { pr("\033[32m"); }
void Ye() { pr("\033[33m"); }
void BL() { pr("\033[34m"); }
void Pu() { pr("\033[35m"); }
void DG() { pr("\033[36m"); }
void Wh() { pr("\033[37m"); }
void Bo() { pr("\033[1m"); }
#include <thread>
#include <mutex>
typedef long long ll;
using namespace std;
using namespace chrono;
string args[10], targ[10];
 
int cnt;
bool no_com = 0, out_ac = 0, qstop = 0;
int cas = 1000; double t = 1000; bool fast = 0; bool fast2 = 0; bool online = 0;
int mem = 128 * 1024; int Max = 10;
queue<thread> q;
 
bool Compile(string filename, string tf) {
    if (sys("g++ " + tf + ".cpp -o " + filename + " -Wall -Wno-unused-result -DDEBUG -DDP " + (fast ? " -O2" : (fast2 ? "" : " -O2 -fsanitize=address,undefined")) + (online ? "" : " -DONLINE_JUDGE"))) return Bo(), 0;
    Bo(), Gr(), ps("Done"), Bl();
    return 1;
}
 
mutex m;
double cpp_tot = 0, std_tot = 0, rd_tot = 0;
ll cpp_mem = 0, std_mem = 0, rd_mem = 0;
int cas_tot = 0, unac_tot = 0;
 
bool Test(int i) {
    char s = 'P', s2 = 'P';
    double cpp = NAN, std = NAN, rd = NAN;
    int cppm = -1, stdm  = -1, rdm = -1;
    FILE * fe; int ret; char tmp[34];
    // run rand
    string tm = (string) "./data/tm" + to_string(i).c_str() + ".log";
    ret = sys("ulimit -s " + to_string(mem + 100) + " && /usr/bin/time -f \"%e %M\" -o " + tm + " ./" + args[3] + " > ./data/rd" + to_string(i));
    if (ret) goto out;
    fe = fopen(tm.c_str(), "r"); fscanf(fe, "%lf%d", &rd, &rdm); rd *= 1000; fclose(fe);
    // run cpp
    ret = sys("ulimit -s " + to_string(mem + 100) + " && timeout 2> sb " + to_string(t / 1000 + 0.3) + " /usr/bin/time -f \"%e %M\" -o " + tm + " ./" + args[1] + " < ./data/rd" + to_string(i) + " > ./data/cpp" + to_string(i));
    if (ret == 31744) { s = 'T'; goto out; }
    if (ret == 35584) { s = 'M'; goto out; }
    if (ret) { s = 'R'; goto out; }
    fe = fopen(tm.c_str(), "r"); fscanf(fe, "%lf%d", &cpp, &cppm); cpp *= 1000; fclose(fe);
    if (cpp >= t) { s = 'T'; goto out; }
    if (cppm > mem) { s = 'M'; goto out; }
    // run std
    ret = sys("ulimit -s " + to_string(mem + 100) + " && timeout 2> sb " + to_string(t / 1000 + 0.3) + " /usr/bin/time -f \"%e %M\" -o " + tm + " ./" + args[2] + " < ./data/rd" + to_string(i) + " > ./data/std" + to_string(i));
    if (ret == 31744) { s2 = 'T'; goto out; }
    if (ret == 35584) { s2 = 'M'; goto out; }
    if (ret) { s2 = 'R'; goto out; }
    fe = fopen(tm.c_str(), "r"); fscanf(fe, "%lf%d", &std, &stdm); std *= 1000; fclose(fe);
    if (std >= t) { s2 = 'T'; goto out; }
    if (stdm > mem) { s2 = 'M'; goto out; }
    // diff
    if (sys("diff -Z ./data/cpp" + to_string(i) + " ./data/std" + to_string(i) + " > ./data/diff.log")) s = s2 = 'W';
    else s = s2 = 'A';
    // output
    out:
    lock_guard<mutex> Lock(m);
    ++cas_tot;
    if (s != 'A') ++unac_tot;
    if (s == 'A') cpp_tot += cpp, std_tot += std, rd_tot += rd, cpp_mem += cppm, std_mem += stdm, rd_mem += rdm;
    if (s != 'A' || out_ac) {
        if (s == 'A') Gr();
        else if (s == 'T' || s2 == 'T') Ye();
        else if (s == 'R' || s2 == 'R') Pu();
        else if (s == 'M' || s2 == 'M') BLK();
        else if (s == 'W') Re();
        pr("%03d ", i);
        putchar(s), putchar(' '), putchar(s2);
        pr(" %.0lfms %.0lfms %.0lfms %dMB %dMB %dMB\n", rd, cpp, std, rdm / 1024, cppm / 1024, stdm / 1024), Bl();
        if (qstop && s != 'A') { Wall, abort(); }
    }
    if (s != 'P' && s2 != 'P') sys(("rm " + tm).c_str());
    if (s != 'P') sys("rm ./data/cpp" + to_string(i));
    if (s2 != 'P') sys("rm ./data/std" + to_string(i));
    if (s == 'A') sys("rm ./data/rd" + to_string(i));
    return 0;
}
 
int main(int argv, char **argc) {
    Bo(), sys("rm -f ./data/*");
    for (int i = 1; i < argv; ++i) {
        string tmp = argc[i];
        if (tmp == "-n") no_com = 1;
        // no_com complie
        else if (tmp == "-l") ++i, cas = stoi(string(argc[i]));
        // testcases
        else if (tmp == "-t") ++i, t = stoi(string(argc[i]));
        // time limit
        else if (tmp == "-f") fast = 1;
        // fast mode (no_com fsanitize)
        else if (tmp == "-ff") fast2 = 1;
        // fast2 mode (no_com O2 & fsanitize)
        else if (tmp == "-m") ++i, mem = stoi(string(argc[i])) * 1024;
        // memory limit
        else if (tmp == "-a") out_ac = 1;
        // echo accept message
        else if (tmp == "-s") qstop = 1;
        // immediately stop when unaccepted
        else if (tmp == "-c") ++i, Max = stoi(string(argc[i]));
        // max number of threads
        else if (tmp == "-o") online = 1;
        // not online judge
        else args[++cnt] = argc[i];
    }
    targ[1] = args[1], targ[2] = args[2], targ[3] = args[3];
    pr("%scpp: %s%s.cpp\n", Pus, BLs, args[1].c_str());
    pr("%sstd: %s%s.cpp\n", Pus, BLs, args[2].c_str());
    pr("%srand: %s%s.cpp\n", Pus, BLs, args[3].c_str());
    if (fast) pr("%sFast Mode %sOn\n", Pus, BLs), pr("%sFsanitize %sDisabled\n", Pus, BLs);
    else if (fast2) pr("%sFast II Mode %sOn\n", Pus, BLs), pr("%sO2 %sDisabled\n", Pus, BLs), pr("%sFsanitize %sDisabled\n", Pus, BLs);
    if (no_com) pr("%sCompile %sDisabled\n", Pus, BLs);
    pr("%sTest Count: %s%d\n", Pus, BLs, cas);
    pr("%sThread Number: %s%d\n", Pus, BLs, Max);
    pr("%sTime Limit: %s%dms\n", Pus, BLs, int(t));
    pr("%sMemory Limit: %s%dMB\n", Pus, BLs, mem / 1024), Bl();
    Wall;
    if (!no_com) {
        COM(cpp); if (!Compile(args[1], targ[1])) CE(cpp);
        COM(std); if (!Compile(args[2], targ[2])) CE(std);
        COM(rand); if (!Compile(args[3], targ[3])) CE(rand);
    }
    Pu(), ps("Now Begin Test"), Bl(), Wall;
    steady_clock::time_point t1, t2; duration<double> ut;
    t1 = nnow;
    for (int i = 1; i != (cas + 1); ++i) {
        if ((int) q.size() > Max) q.front().join(), q.pop();
        q.push(thread(Test, i));
        if (i % 100 == 0) {
            lock_guard<mutex> Lock(m);
            int ac = cas_tot - unac_tot;
            printf("%s%d %sCases, %s%d %sWrongs, %s%.2lf%%%s\n", BLs, cas_tot, Pus, BLs, unac_tot, Pus, BLs, ac * 1.0 / cas_tot * 100, Pus);
            t2 = nnow; ut = dc;
            printf("Total: %s%.3lfs\n", BLs, ut.count());
            printf("%sAverage: %s%.0lfms %.0lfms %.0lfms %.0lfMB %.0lfMB %.0lfMB\n", Pus, BLs, rd_tot / ac, cpp_tot / ac, std_tot / ac, 1.0 * rd_mem / ac / 1024, 1.0 * cpp_mem / ac / 1024, 1.0 * std_mem / ac / 1024), Bl();
            Wall;
        }
    }
    while (!q.empty()) q.front().join(), q.pop();
    t2 = nnow; ut = dc;
    int ac = cas_tot - unac_tot;
    printf("%s%d %sCases, %s%d %sWrongs, %s%.2lf%%%s\n", BLs, cas_tot, Pus, BLs, unac_tot, Pus, BLs, ac * 1.0 / cas_tot * 100, Pus);
    printf("Total: %s%.3lfs\n", BLs, ut.count());
    printf("%sAverage: %s%.0lfms %.0lfms %.0lfms %.0lfMB %.0lfMB %.0lfMB\n", Pus, BLs, rd_tot / ac, cpp_tot / ac, std_tot / ac, 1.0 * rd_mem / ac / 1024, 1.0 * cpp_mem / ac / 1024, 1.0 * std_mem / ac / 1024), Bl();
    Bl(), Wall;
    sys("rm -f ./data/.f*");
    sys("rm sb");
    Gr(), ps("Finished"), Bl(), Wall;
}

编译时需要先加上 -pthread,运行时的前三个参数必须依次是自己的代码,正解,数据生成器(省略扩展名,默认为 .cpp),注意使用标准输入输出
还有一些常用的参数:

  • -l n 将测试点数量设置为 \(n\)(默认为 \(1000\))。
  • -t tl 将时间限制设置为 \(tl\) ms(默认为 \(1000\) ms)。
  • -m ml 将空间限制设置为 \(ml\) Mib(默认为 \(128\) Mib)。
  • -c m 将线程数设置为 \(m\) (默认为 \(10\))。
  • -f 开启 O2 优化。
  • -ff 开启 O2 优化和 Sanitizer。
  • -a 返回 Accepted 信息。
  • -s 出现 Unaccepted 后立即终止。

参考

多线程对拍
算法竞赛进阶指南

标签:std,pr,浅谈,tot,cpp,data,string
From: https://www.cnblogs.com/blog21012004/p/18110819

相关文章

  • 浅谈JVM整体架构与调优参数
    本文分享自华为云社区《【性能优化】JVM整体架构与调优参数说明》,作者:冰河。JVM的分类这里,我们先来说说什么是VM吧,VM的中文含义为:虚拟机,指的是使用软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统,是物理机的软件实现。常用的虚拟机有:VMWare、......
  • 浅谈AI未来发展趋势与挑战
    对于AI大模型未来发展趋势与挑战的个人看法:1、未来的发展趋势:AI大模型未来发展趋势可以从以下几个关键方面来讨论:1. 能源与计算效率绿色计算与节能技术:随着硬件技术的发展,预计未来的AI大模型将进一步降低能源消耗,采用更高效的处理器、专门针对AI任务设计的定制芯片(如TPU......
  • 浅谈Windows发展史
    简介从微软发布Windows1.0开始,到现在已经有快40年历史了,接下来让我们浅浅的谈一下微软的发展史(只记录大家都知道的)Windows1.0Windows1.0是微软于1985年11月20日发布的操作系统,这也是微软第一个图形化操作系统。基本的功能也是有了。Windows2.0Windows2.0是微软于1987......
  • [树上背包浅谈]
    树上背包在这个树中选取一定数量的点或边(也可能是其他属性),使得某种与点权或者边权相关的花费最大或者最小。解决这类问题,一般要考虑使用树上背包。dp[i][j]表示在以i为根的树中选择j个结点所获得的最大值/最小值有线电视网#include<cstdio>#include<cstring>#include<ios......
  • 浅谈循环依赖
    说明循环依赖是一个大家讨论很多的话题,它更多是一个工程上的问题而不是技术问题,我们需要首先有一定的认知:如同两个人相互帮忙,两个类之间你调用我的,我调用你的是很正常也很自然的需求模型。单一依赖确实有好处,改动一个最顶层类时不需要在意对底部类的影响,但是从本来就自然的......
  • 浅谈数据治理之道 数据运用(四)
    前面我们谈到了数据分析,数据运用是数据分析的延伸,是将分析得出的洞见转化为实际行动的过程。那么我们需要进一步的将分析出来的数据进行运用,这也是非常关键的一个动作,也是数据价值所在。只有用数据来发现和解决问题,数据就变得非常有用了。那么面对从海量数据中提取价值、确保......
  • 浅谈WPF之属性系统
    在WPF开发中,经常听到各种属性,如:依赖属性,附加属性,CLR属性,那这些不同类型的属性,具体又有什么作用呢?今天以一些简单的小例子,简述一下WPF开发中,各种属性的相关概念和应用,仅供学习分享使用,如有不足之处,还请指正。 CLR属性 CLR属性(CommonLanguageRuntime),又称为.Net标准属性,是......
  • 浅谈C# Linq里的FirstOrDefault,First,Single,SingleOrDefault 方法
    FirstOrDefault:返回第一个元素,如果为空,则返回类型的默认值;数值类型默认值是0,引用类型默认值是NULL,布尔类型默认值是FalseFirst:也是返回第一个元素,但是如果为空的话,会抛出异常!!Single:返回唯一一个符合条件的元素,如若没有或者有多条,都会抛出异常!SingleOrDefault:返回唯一一个......
  • [docker] 浅谈Docker:网络模式及从容器内部访问宿主机的IP地址
    0序本文系转载参考文献,属于非原创的笔记类博文。最新结论:从Docker容器内部访问宿主的IP地址的几种方法,推荐基于Bridge模式+--link访问别的服务+172.16.0.1(访问宿主机)。1Docker的网络模式docker是比较流行的容器技术,docker镜像方便程序员对应用统一的要求,打包部......
  • [docker] 浅谈Docker:Docker容器中环境变量的应用
    0序1设置环境变量1.1场景:在Dockerfile中设置环境变量在构建Docker镜像时,可以在Dockerfile中使用ENV指令来设置环境变量ENVMY_ENV_VAR="ABC123"ENV指令用于设置环境变量,语法为ENV<key><value>ENV<key>=<value>1.2场景:使用dockerrun命令设置环境变量使用d......