C语言实现控制台迷宫:DFS生成与自动求解实战
前阵子闲着没事想用C语言写点能玩的东西。学生管理系统、图书借阅系统写得太多实在提不起兴趣。后来想到走迷宫小游戏它不需要任何图形库控制台就能画出效果核心算法还是教科书里的深度优先搜索DFS正好把“生成迷宫”和“求解迷宫”两件事一起办了。我把整个实现过程整理了一遍从数据结构设计、递归回溯的细节到玩家移动、渲染循环、自动求解再到我踩过的几个坑全都放在下面。如果你在学C语言或者想找个小项目练手这篇文章可以直接照着敲。1. 棋盘建模一堵墙、一条路怎么用C语言表示写迷宫第一步不是写算法而是先把地图的数据结构定好。数据结构选对了后面所有逻辑都会顺很多。我这边选的是二维字符数组没用位图也没用链表。1.1 为什么是二维字符数组迷宫本质上是一个由行和列组成的网格二维数组天然就是这个结构。每个格子有两种状态是墙还是路用一个char变量就够了我用#表示墙空格表示路。这样做的好处是打印迷宫的时候直接循环输出字符不需要任何转换。调试的时候打开终端迷宫长什么样一眼就能看出来。也有人用int数组0和1表示路和墙最后打印再转成字符。功能上没有区别但字符数组省一层转换写起来更省事。C语言里char本身就是数字进行判断和比较也不比int麻烦。提示如果某个格子未来要叠加多种状态比如被玩家走过、被标记为路径字符数组也可以扩展用不同的字符表示不同状态比如表示玩家$表示终点.表示求解路径。这种字符映射的方式在控制台小游戏里非常实用。1.2 三个关键约定21×21、坐标轴、全墙填充定义迷宫尺寸为#define ROWS 21 #define COLS 21为什么是21而不是20因为深度优先生成迷宫的时候每次是隔一个格子凿墙。为了让起点、终点和路径都落在可通行的格子上迷宫的行列数必须是奇数。如果是一个20×20的地图你从(1,1)出发隔2格走路径会卡在边界附近处理起来很难受。21×21意味着内部有10×10个可被打通的单元生成的迷宫规模适中控制台一屏也能放下。坐标方面我统一用maze[y][x]y表示行x表示列。刚开始写很容易搞反尤其是在方向数组里。记住第一个下标是行第二个下标是列。玩家坐标我单独用playerX和playerY同样x对应列y对应行。初始化的时候先把所有格子填成墙void initMaze() { for (int y 0; y ROWS; y) { for (int x 0; x COLS; x) { maze[y][x] #; } } }这里顺手多说一句外围的一圈墙不要额外设置因为初始化后整张图全是墙之后DFS只会在边界内部打通路天然就留下了外墙。这样判断越界时只要要求下一个格子的坐标在1到ROWS-2之间就能保证不会跑到地图外面去。2. 深度优先算法的核心递归回溯生成迷宫这一部分是整个游戏最核心的地方。理解了这个迷宫生成就掌握了一半。2.1 打通墙的思路隔一格凿一锤深度优先生成迷宫的原理一句话描述就是从起点开始随机选一个方向向前跨两格如果那个格子还是墙就把中间这格和对面那格都打通然后跳到对面那格继续重复。一直走到无路可走再退回上一个岔路口换一个方向。注意是“跨两格”。比如当前格子在(1,1)选择向右那么目标格子是(1,3)中间需要打通的墙是(1,2)。打通后从(1,1)走到了(1,3)。为什么一定要隔一格因为如果一格一格地走整张图全部被挖空没有墙也就谈不上迷宫了。隔一格挖路才会形成网格状的通道和墙体。2.2 随机方向和未访问判断迷宫多样性的来源如果每一步都按固定方向顺序走生成的迷宫会千篇一律几乎每次都是同一条螺旋通道。为了让每次生成都不同需要在递归之前把四个方向随机打乱。还有一个关键判断目标格子必须是墙#。这个条件保证了当前通路不会和已经生成的通路交叉成环。如果目标格子已经是路说明那里已经被探测过了再打通就会破坏迷宫的单路径属性。深度优先生成出来的迷宫属于“完美迷宫”任意两点之间有且只有一条通路这是迷宫游戏最经典的形态。完整代码如下void carve(int x, int y) { maze[y][x] ; // 上、下、左、右对应的行和列偏移量 int dirs[4][2] {{-2, 0}, {2, 0}, {0, -2}, {0, 2}}; // 洗牌把四个方向随机换位置 for (int i 0; i 4; i) { int r rand() % 4; int tmp0 dirs[i][0], tmp1 dirs[i][1]; dirs[i][0] dirs[r][0]; dirs[i][1] dirs[r][1]; dirs[r][0] tmp0; dirs[r][1] tmp1; } for (int i 0; i 4; i) { int ny y dirs[i][0]; int nx x dirs[i][1]; // 必须在边界内部并且目标格还是墙 if (nx 0 nx COLS - 1 ny 0 ny ROWS - 1 maze[ny][nx] #) { // 打通当前格到目标格之间的墙 maze[y dirs[i][0] / 2][x dirs[i][1] / 2] ; carve(nx, ny); } } }主函数里这样调用srand((unsigned)time(NULL)); initMaze(); carve(1, 1);调用完整个迷宫就生成了。起点在左上角内部终点我一般设置在右下角内部也就是(ROWS-2, COLS-2)。你可以把终点坐标单独存起来方便后面判断胜利。2.3 递归深度与性能为什么21×21不会爆栈有些初学者会担心递归无限调用。其实不会因为每次调用都会把一个新的格子改成路而全部格子数量有限递归到没有可挖的方向就会自然返回。递归的最大深度大约是可通行格子数的一半21×21的迷宫最多几百层调用远小于函数栈的承受范围。如果某天你想生成特别大的迷宫比如201×201递归深度可能到上万层就容易爆栈。这时候可以改成显式栈本质上是用堆内存模拟递归。这个在后面的扩展部分我会再提。2.4 路径的天然结构为什么DFS适合生成迷宫深度优先搜索总是沿一条路走到黑撞墙后回头继续找。这使得生成出的迷宫通道长、岔路少玩家容易迷路但又不至于无解。像随机Prim或Kruskal这类算法生成的是偏向密路网的迷宫岔路多、环路多玩家的迷路感更多来自绕圈。从游戏体验上说DFS生成的迷宫更有“柳暗花明”的感觉你可能走了一条很长的死路最终不得不回头但一旦找到正确路径往往一条路直达终点。3. 让玩家动起来渲染循环与实时输入迷宫生成只是静态地图。要变成游戏还需要循环清屏、画迷宫、读按键、移动角色、判断胜负。3.1 控制台画布清屏与打印每一帧都先清屏再按行列打印。我用的字符映射是#墙空格路玩家$终点。打印时实时判断void draw() { system(cls); // Windows下清屏Linux/macOS用 system(clear) for (int y 0; y ROWS; y) { for (int x 0; x COLS; x) { if (x playerX y playerY) { printf(); } else if (x finishX y finishY) { printf($); } else { printf(%c, maze[y][x]); } } printf(\n); } printf(WASD移动按Q退出\n); }这里有个细节起点位置不要额外设置成特殊字符直接用玩家坐标覆盖。否则起点会显示成一个无法移动的标记影响视觉。终点的字符会被打印在对应格子上如果玩家走到终点玩家字符会盖住终点字符不过这并不影响胜负判断。3.2 移动逻辑撞墙检测怎么写玩家输入w时试图向上走一格。先判断目标格子是不是墙不是墙才允许移动void movePlayer(char key) { int nx playerX, ny playerY; switch (key) { case w: ny--; break; case s: ny; break; case a: nx--; break; case d: nx; break; } if (maze[ny][nx] ! #) { playerX nx; playerY ny; } }因为迷宫的外墙全是#这个判断自然把玩家限制在地图内不需要额外检查边界。这是一个很省心的设计只要把地图四周保持为墙移动检测就变得很干净。如果你以后改成读文件加载迷宫也要保证迷宫外围有一圈墙这个前提条件别丢。3.3 输入处理getchar不够用按一下就得动C标准库的getchar需要按回车才会返回玩起来很迟钝。想要按一个键立刻反应需要平台相关的API。Windows下用conio.h里的_getch()#include conio.h char key _getch();Linux/macOS下标准库没有现成函数一种简单做法是用termios把终端设置成原始模式#include termios.h #include unistd.h int getch(void) { struct termios oldt, newt; int ch; tcgetattr(STDIN_FILENO, oldt); newt oldt; newt.c_lflag ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, newt); ch getchar(); tcsetattr(STDIN_FILENO, TCSANOW, oldt); return ch; }这段代码把终端从行缓冲模式临时切到原始模式读取一个字符后立刻恢复。在游戏主循环里调用它就能实现“按一下动一格”的即时反馈。注意调用完要恢复终端设置否则程序结束时终端会处于无法正常输入的状态。注意Windows和Linux下的清屏命令不一样。如果代码要跨平台可以写成条件编译#ifdef _WIN32 #define CLEAR cls #else #define CLEAR clear #endif3.4 主循环与胜负判定主循环做的事情不多画迷宫读按键按WASD更新坐标每次移动后检查玩家是否到达终点while (1) { draw(); char key getch(); if (key q) break; movePlayer(key); if (playerX finishX playerY finishY) { draw(); printf(恭喜你走出迷宫\n); break; } }注意调用getch后方向键在某些终端上会返回两个字节第一字节是ESC。如果要用方向键处理会更麻烦。所以我直接用WASD省心。另一个小细节玩家输入大写WASD时程序不识别。可以在movePlayer入口处统一转成小写比如if (key A key Z) key 32;。4. 自动求解让深度优先算法再表演一次生成迷宫用DFS求解迷宫也可以用DFS。同一套算法用两次这个设计很划算。4.1 求解思路从玩家位置找终点生成迷宫时我们要求任意两点之间只有一条通路。求解时只需要从玩家当前坐标出发沿着四个方向一格一格探索遇到墙就绕开继续递归直到到达终点。为了避免在死胡同里转圈需要把已经走过的格子标记为一种状态比如v。4.2 带路径输出的递归求解我写了一个返回值为1表示找到路径的求解函数int solve(int x, int y) { if (x finishX y finishY) { return 1; } maze[y][x] v; // 标记已访问 int dirs[4][2] {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; for (int i 0; i 4; i) { int nx x dirs[i][1]; int ny y dirs[i][0]; if (nx 0 nx COLS ny 0 ny ROWS maze[ny][nx] ) { if (solve(nx, ny)) { maze[y][x] .; // 当前格子是成功路径的一部分 return 1; } } } return 0; }注意这里判断maze[ny][nx] 所以已经标记为v的格子不会被重复走。当递归找到终点后会在归来的路上把每一个父格子标记成.最终从起点到终点连成一条.路径。调用方式solve(playerX, playerY); draw();draw函数里需要增加对.的打印逻辑如果maze[y][x] .输出.。4.3 自动演示路径先求再动画如果你不满足于只显示静态路径还可以做一个自动走的演示。思路很简单求解完成后从起点出发沿.方向一步步移动每次移动都重绘并短暂暂停。这个功能很适合展示算法完成度也可以用来验证迷宫是否一定可解。关于暂停可以用标准库usleepLinux或SleepWindows同样可以条件编译。这个部分不用太复杂知道思路就行。实际操作时我是在玩家选项里加了一个“自动演示”分支按A键触发触发后程序依次显示路径上的每个点视觉上就像有人在自动走迷宫。5. 踩坑记录那些让程序神秘崩溃的细节这部分是我最想说的。看起来逻辑很顺实际写的时候还是踩了不少坑。5.1 数组越界边界检查多写一层判断第一次写carve时我只判断了maze[ny][nx] #没有检查nx和ny是否在边界内。结果递归到地图边缘时ny变成-1程序直接访问了未定义内存有时崩溃有时打印乱码。这种问题C语言不会主动提醒你只有经验积累下来才知道边界判断要写全。正确的判断是nx 0 nx COLS - 1 ny 0 ny ROWS - 1 maze[ny][nx] #。因为外墙不能被打通所以不是0而是0。写下这个条件时我脑子里会过一遍边界情况如果nx是0说明到了最左边一列那是外墙不能动如果nx是COLS-1同样是最右边外墙。只有1到COLS-2才是内部可以碰的区域。5.2 不写srand每次迷宫都一样rand()是伪随机数生成器如果不设置随机种子每次运行生成的迷宫序列完全相同。你没看错第一次运行和第十次运行生成的迷宫完全一样。这个现象第一次遇到时我以为是bug。解决办法就一句话srand((unsigned)time(NULL));放在main函数最前面。time.h头文件别忘了加。5.3 清屏命令闪屏与控制台光标残留循环里每帧调用system(cls)屏幕会闪。小尺寸迷宫还好大迷宫闪得厉害。可以尝试不调system而是用ANSI转义序列控制光标位置进行局部刷新比如printf(\033[H);把光标移到左上角再重新打印。这个在Windows 10以上的终端也支持。还有个常见问题是玩家移动后原来位置的消失但如果你只修改坐标而不重绘角色会拖出残影。我的做法是全屏重绘简单粗暴不会出错。屏幕闪烁在21×21这种尺寸下其实不明显可以接受。5.4 递归求解时用错了访问标记求解时如果标记已访问的字符是#会永久覆盖墙或路导致求解后地图损坏游戏没法继续玩。我后来单独用了v和.两个字符再看迷宫时也能直观看到算法走过的路径。另外如果你在求解函数的递归过程中没有在失败时恢复格子状态那你需要在递归返回时把v改回空格否则会影响其他分支的探索。但我在上面的写法里没有恢复因为我保留了visited标记避免了重复探索性能更好而且不影响最终路径的正确性。6. 从“能跑”到“好玩”后续可以考虑的扩展迷宫程序基本完成了但离“好玩”还有距离。这里提供几个我验证过可行的方向。6.1 从完美迷宫到非完美迷宫DFS生成的迷宫没有环路从起点到终点只有一条路。这种迷宫玩起来比较“线性”有时候玩家走到死胡同只能原路返回耐心差点的人容易烦躁。非完美迷宫会多开一些额外的墙形成回路让玩家有更多选择空间。可以在DFS生成后随机挑一些墙打通注意不要破坏整体结构。实现很简单遍历迷宫对每个内部墙格子如果它左右两侧都是路或者上下两侧都是路就有一定概率把它打成路。这样就会形成环。6.2 难度分级尺寸、算法和障碍物最简单的分级方法是改ROWS和COLS。15×15适合新手31×31适合挑战。也可以在同一尺寸下增加“陷阱”比如某些路格踩上去会传送回起点或者计时模式。控制台游戏能做的事其实不少。我试过在迷宫里随机放一些“暗格”踩到会显示一行提示算是彩蛋。这种扩展不需要动算法只改渲染和碰撞检测逻辑就行。6.3 显式栈替代递归当迷宫尺寸调到101×101以上时递归深度可能达到几千层虽然依然在栈上限内但生成耗时明显。用显式栈模拟递归能更好地控制内存也能方便加入“逐步演示生成过程”的功能。核心思路是把要处理的格子压进栈然后循环pop、判断、压栈。如果你对递归调用栈理解得扎实改成显式栈并不难。我简单写一个框架思路// 伪代码示意栈里存坐标开始时压入(1,1) while (栈不为空) { 弹出栈顶坐标(curX, curY); 当前格设为路; 随机打乱方向; 遍历每个方向: 如果目标格是墙且在边界内: 打通中间墙; 把目标格压栈; }这个写法和递归版本质一样只是把系统函数栈换成了自己管理的数组。调试时甚至可以把每一步的栈状态打印出来观察算法进度。到这里一个完整的C语言迷宫小游戏就整理完了。你完全可以按我上面的代码敲一遍然后自己调尺寸、改字符、加功能。我再多说一句体会把递归原理理解透比背代码重要得多。当你看到carve函数那几行递归时脑子里应该能画出函数调用和返回的路径能力就上来了。如果你在Linux下编译别忘了给终端恢复模式如果你在Windows下用Visual Studio记得把项目字符集改成多字节字符集否则一些控制台函数行为会很奇怪。最后祝你玩迷宫玩得开心。

相关新闻

Agent记忆管理实战:从全量拼接陷阱到分层存储与向量检索

Agent记忆管理实战:从全量拼接陷阱到分层存储与向量检索

1. 从一个真实翻车现场说起去年冬天,我帮一个做智能客服的朋友排查线上问题。他们的系统接了一个大模型驱动的对话 Agent,上线头两周效果惊艳,第三周开始用户投诉量暴涨——同一个用户反复问同一个问题,Agent 每次回答都不一样&am…

2026/10/14 21:15:55 阅读更多 →
Java Swing桌面礼物编程实战:从窗口搭建到打包发布

Java Swing桌面礼物编程实战:从窗口搭建到打包发布

简介:面向初、中级Java开发者的生日礼物小项目,适合想用编程表达心意、探索Swing/JavaFX图形界面与Java Sound音频开发的程序员。压缩包共109个文件,包含13个Java源文件、14个编译后的class文件、62张PNG图片素材、2个MP3音频,以及…

2026/10/14 21:15:55 阅读更多 →
AI高薪风口来袭!小白程序员如何抓住机遇,收藏这份学习指南?

AI高薪风口来袭!小白程序员如何抓住机遇,收藏这份学习指南?

文章主要介绍了AI行业的薪资现状,从实习生日薪5000元到年薪上亿,AI人才市场正在经历一场白热化的争夺战。文章指出,AI正在“入侵”每一个行业,人才缺口超过500万,普通人有机会分到一杯羹。文章建议普通人通过系统学习掌…

2026/10/14 21:14:53 阅读更多 →

最新新闻

8-PSK数字通信系统Matlab仿真完整实现与误码率分析

8-PSK数字通信系统Matlab仿真完整实现与误码率分析

前阵子帮一位同学调试一套基于8-PSK调制的数字通信系统仿真项目,顺手把手头的代码整理了一遍,发现8-PSK这东西看起来只是比QPSK多了四个星座点,真正把发射端、AWGN信道、接收端解调和误码率统计完整跑通,里面还是有不少坑的。这篇…

2026/10/14 22:10:30 阅读更多 →
狼羊白菜问题的AI建模:位编码+状态搜索实战

狼羊白菜问题的AI建模:位编码+状态搜索实战

简介:本资源是一份面向人工智能与算法入门学习者的经典逻辑推理题详解文档,聚焦“农夫带狼、羊、白菜过河”这一状态空间搜索典型问题,适用于计算机科学课程设计、AI基础算法实训及编程思维训练场景。文档系统阐述了问题建模方法(…

2026/10/14 22:10:30 阅读更多 →
Agent工程栈落地实践:任务编排、工具调用与状态管理

Agent工程栈落地实践:任务编排、工具调用与状态管理

1. 从五条动态里拆出来的工程信号10月7日那天,我刷到一位长期跟踪智能体方向的从业者连发了五条动态。内容不算长,但信息密度很高——没有一条在讲模型参数又涨了多少,全都在聊“怎么把一堆能力串起来跑通”。这个信号其实比任何单点技术突破…

2026/10/14 22:10:30 阅读更多 →
ASP.NET C/S架构邮件收发系统:SMTP/POP3协议实现与毕设实战

ASP.NET C/S架构邮件收发系统:SMTP/POP3协议实现与毕设实战

简介:本资源为计算机专业毕业设计参考项目,主题是基于ASP.NET与C/S架构的电子邮件简单收发系统,面向需要完成毕设或课程设计的高校学生及.NET初学者。项目围绕SMTP与POP3协议实现邮件发送与接收,并包含用户注册、地址簿管理&#…

2026/10/14 22:10:30 阅读更多 →
JPG转MIF/TXT/COE:FPGA图像初始化文件的Matlab生成指南

JPG转MIF/TXT/COE:FPGA图像初始化文件的Matlab生成指南

做FPGA图像处理的人,迟早会被同一个问题拦住:手里有一张JPG图片,怎么把它变成FPGA里ROM能认识的数据?这种需求太常见了——图像采集模块要仿真、边缘检测算法要输入测试图、神经网络加速模块要加载权重,甚至做一个简单…

2026/10/14 22:10:30 阅读更多 →
2026年青岛栈桥怎么玩?本地人推荐这5家必吃馆子

2026年青岛栈桥怎么玩?本地人推荐这5家必吃馆子

每年夏天,青岛栈桥总是游人如织。但说实话,大部分游客的体验都停留在“看海、拍照、吃烧烤”三件套,真正能吃到青岛本地味道的,少之又少。作为在青岛生活多年的“老土著”,今天不聊景点路线,就聊吃——栈桥…

2026/10/14 22:09:29 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →