C++对拍即调试技巧

一、生成数据

若是生成数据输出文件操作应写成 freopen("something.in","w",stdout);

\(1.\) 生成随机序列

int p[N];
for(int i=1;i<=n;i++) p[i]=i;
random_shuffle(p+1,p+n+1);//打乱一个数组
for(int i=1;i<=n;i++) cout<<p[i]<<" ";

这样生成一个 \(1 \sim n\) 的随机排列

\(2.\) 生成随机一棵树

for(int i=2;i<=n;i++)
    cout<<rand%(i-1)+1<<" "<<i<<endl;

这样生成一棵以 \(1\) 为根的树

\(3.\) 生成随机无自环无重边的无向图

//预定n为点数,m为边数
set<pair<int,int> >s;//边的集合
for(int i=1;i<=m;i++)
{
    int from=rand%n+1,to=rand%n+1;
    if(from==to)//判自环
    {
        i--;
        continue;
    }
    if(s.count(make_pair(from,to))||s.count(make_pair(to,from)))//判重边,如果是有向图把后面(to,from)的删掉
    {
        i--;
        continue;
    }
    s.insert(make_pair(from,to));//加入边的集合
    cout<<from<<" "<<to<<endl;//输出
}

生成一个 \(n\) 个点,\(m\) 条边,无自环无重边的无向图


二、对拍程序怎么写

我们令数据生成器、自己猜想的正解与暴力放在同一个根目录下

令数据生成器可执行文件的文件名名为 produce,自己猜想的正解可执行文件名为a,暴力可执行文件名为ba 的输出文件为 A.outb 的输出文件为 B.out (Linux下可执行文件文件名没有后缀,Windows下为.exe

对拍程序 check.cpp 写法如下:(要对拍直接运行 check 即可,默认在Linux下运行

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int cnt=0;//统计对的个数
    while(true)
    {
        system("./produce");
        system("./a");
        system("./b");//运行produce,a,b三个程序
        if(system("diff A.out B.out"))//比较A.out与B.out,如果不一样会返回1(Linux下)
        {
            puts("WA");
            return 0;
        }
        else printf("AC %d\n",++cnt);//对的个数加1
    }
    return 0;
}
//另外,想要停止要按 Ctrl + Z

数据生成器除了用来生成数据进行对拍外,还可以用来测试时间复杂度是否正确。生成一组极限数据, 然后在 \(\text{Linux}\) 下使用命令 time 来测试程序运行的时间

比如假设正解名称还是上文中的 a.cpp,那可以在控制台输入命令:

time ./a

返回时会由上到下返回三个时间:\(\text{real,user,sys}\)

其中 \(\text{user}\) 是程序将要评测机上运行的时间,如果 \(\text{user}\) 所指的时间大于题面要求时限,说明程序 百分百\(\text{TLE}\)


三、调试

\(1.\) 输出中间变量调试

输出变量以调试,直到找到出错的部分

建议输出加一些提示的信息

这就不详细讲了吧……?

\(2.\) 单步调试 \(GDB\)

这个默认在 Windows 下调试,而且所涉及的 路径名文件名不可以有空格

首先得找到并编译文件,按 Win + R 在里面输入 cmd

先切换到文件所在的硬盘,在终端里输入 硬盘 :,比如D盘输入 D:

然后再复制要编译调试的文件所在的文件夹的位置,在终端里输入 cd 路径名,比如输入 D:\vscode_code

再编译文件。编译格式:g++ -g -o 生成可执行文件名.exe 要编译的文件名.cpp(本文默认 C++PythonC等也行)

然后如果想运行的话,直接输入可执行文件名.exe 即可

若想调试则输入 gdb 可执行文件名.exe

不懂的可以看这张图,说的就是上面的步骤:(图中的 Temp_the_test.cpp洛谷P1850换教室\(\text{AC}\) 代码)

GDB调试示意图

找到并编辑文件后,我们就可以进入调试时间了!

首先开始调试文件,格式上面已经说过了。

按下回车以后会有很多英文蹦出来,不用担心,这些都是在讲 \(GDB\) 版权(

调试需要记住一些调试指令:

全称 简写 作用
\(\text{list}\) \(\text{l}\) 显示当前程序停止的位置附近的源代码(我试过,我的电脑上最多显示 \(10\) 行)
\(\text{run}\) \(\text{r}\) 从头开始运行程序,直到断点处为止(没有断点的话直接运行完)
\(\text{break}\) \(\text{b}\) 设置断点,后面跟行号,也可以跟函数名(在这个函数这个参数的状态时停止)、\(\text{if}\) 语句(当……时停止)
\(\text{next}\) \(\text{n}\) 执行下一条语句,但不进入函数
\(\text{step}\) \(\text{s}\) 执行下一条语句,如果有函数则执行函数内语句
\(\text{print}\) \(\text{p}\) 在运行到当前行数时显示一个变量或数组的值
\(\text{display}\) \(\text{disp}\) 永久显示一个变量或数组的值,直到程序结束
\(\text{clear}\) \(\text{cl}\) 清除某一行的断点,如果什么都不跟则是清除所有断点
\(\text{undisplay}\) \(\text{undis}\) 后面跟变量的编号(之前显示的 \(\$ 1\) 等,只需要输入序号,不需要输入 \(\$\)),可以不再显示某个变量的值
\(\text{watch}\) \(\text{wa}\) 后面跟变量名,可以在变量发生变化时停止程序运行并输出变化前后的值
\(\text{continue}\) \(\text{c}\) 在程序当前停止的为止继续运行,直到运行到下一个断点处
\(\text{until}\) \(\text{u}\) 从当前位置开始,执行到 \(\text{until}\) 要求的行号或者函数名或者 \(\text{if}\) 条件(不懂得可以看 \(\text{break}\) 语句)
\(\text{Enter(回车)}\) \(\text{无}\) 寻找从输入该回车上方最近的一条明确指示了的语句,执行它

四、总结

\[\text{预祝各位} N O {I} P \\ \\ R P + + \]

posted @ 2022-08-01 21:17  DreamerX  阅读(455)  评论(0)    收藏  举报