同学!你见过会“流血”的算法吗?C++深搜遍历图的每条路径可视化程序!

C++深搜遍历图的每条路径可视化程序.mp4_20260130_150827.397

 

你知道吗?最近我在抖音上刷到一个超燃的视频(号:pxcoding),背景音乐是那首经典的《燃烧的火焰》——对,就是日本《排球女将》的主题曲,一下子就把人拉回了那个热血的70/80年代。

但画面里演的不是小鹿纯子扣球,而是一颗蓝色的小火箭,在黑色背景上嗖嗖地飞,身后拖着红色的尾巴,像血液在血管里流淌一样,从一个点流到另一个点。这就是用C++精灵库(sprites.h)写的一个程序——让它自动找出从A点到C点的所有路径。
这玩意儿到底在搞什么?

简单来说,就是这个C++程序运行后会生成了A、B、C、D、E五个点,把它们两两相连,做成一张网。然后小火箭从A出发,要去C,它要尝试每一条可能的路。最酷的是,这不是枯燥的代码运行,而是一场视觉盛宴:
当小火箭决定前往下一个邻居节点时,它的画笔颜色会变成红色(HSV颜色模式里的H=0,表示颜色的色相为0,即红色),然后放慢速度(speed(1)),缓缓爬过去,真的就像鲜血在黑色的血管网络里缓缓流淌。到了之后,它恢复原速,停顿半秒,让你看清楚它的轨迹。如果走不通?没关系,它开始"时光倒流"——画笔颜色变成青色,以同样的速度缓缓退回去,就像血液回流一样。这种回溯的过程,其实就是计算机里经典的深度优先搜索(DFS)算法的可视化。
你看代码里这段:

visitor.color(0).speed(1).go(nb).speed(0).wait(0.5);

简单几行,就把冷冰冰的算法变成了看得见的"血液流动"。你可能会问,C++精灵库默认的角色为什么是小火箭?🚀
这可不是随便选的。你想啊,小火箭代表着什么?冲破大气层,冲向星辰大海!这库的设计者用心了——它就是给少年们准备的最好的礼物。

说到这,我就想起了最近中国科学院大学成立星际航行学院的新闻。看着屏幕上的小火箭在图结构中穿梭寻找路径,不正是象征着我们这些正值年少的同学们吗?精力旺盛,充满好奇,在知识的网络中探索每一条可能的路径,为了明天的星辰大海做准备。

C++深搜遍历图的每条路径可视化程序.mp4_20260130_150933.404

 

很多人以为学编程就是对着黑框框(命令行)敲枯燥的代码。但C++精灵库完全打破了这种印象:可视化即时反馈:你写的不是抽象的逻辑,而是看得见的小精灵在屏幕上跳舞。

而且这玩意儿真有学习价值!你在玩的过程中,不知不觉就理解了图的遍历、递归回溯、深度优先搜索这些大学数据结构课的核心概念。等真到了课堂上,你脑子里想的不是"vis数组标记访问状态",而是"小火箭变红又变青,血液流过去又流回来"。

同学们,我们的征途是星辰大海。就像这段代码里的小火箭,从A点出发,不畏曲折,遍历每一条可能的路径,最终到达C点。

说到底,C++ 精灵库最棒的地方就是:它把专业的编程逻辑,变成了少年能轻松感知、亲手操作的可视化场景。不用再对着冰冷的代码空想,而是看着自己写的程序,让小火箭在屏幕上 “跑” 起来,这种成就感,比单纯背知识点强一百倍!如果你也觉得编程学习太无聊,不妨试试这个精灵库,用玩的心态学编程,说不定你会发现,原来编程可以这么有趣,原来星辰大海的编程梦,离自己这么近。 想看视频效果,网址在这里:https://www.douyin.com/video/7600985547170958627

以下是这个C++程序的所有代码:

#include "sprites.h"  //包含C++精灵库 
#include <vector>
#include <map>
using namespace std;
Sprite visitor{"res/circle_blue.png"};      //建立角色叫visitor
Sprite pathshower;    //输出路径A->B-C...的角色 
Point A={randint(200,300),randint(200,300)};
Point B={randint(-300,-200),randint(200,300)};
Point C={randint(-300,-200),randint(-300,-200)};
Point D={randint(200,300),randint(-300,-200)};
Point E={0,randint(-350,-330)};
vector<Point> v = {A,B,C,D,E};
vector<Point> path;      //存储路径 
int anscounter = 0;      //存储路径总数 
map<Point,string> dict={{A,"A"},{B,"B"},{C,"C"},{D,"D"},{E,"E"}};//节点:名字的 映射 
map<Point,bool> visited = {{A,false},{B,false},{C,false},{D,false},{E,false} };
map<Point,vector<Point> > graph = { {A,{B,C,D,E}}, {B,{A,C,D,E}}, {C,{A,B,D,E}}, {D,{A,B,C,E}}, {E,{A,B,C,D}} };
void dfs(Point P){  // 深度优先搜索图 
   if(P==C){  //到达终点C,则输出路径 
     anscounter++;
     string cntstr = to_string(anscounter);
     string s = "" + cntstr + "条路径:A";
     for(int i=1;i<path.size();i++)s=s+ "->" + dict[path[i]];
     pathshower.write(s,30);
     visitor.wait(3);
     pathshower.cleartxts(1);  //清除最早写的文字 
     return ;
    } //到了终点C,则等待3秒种
   for(Point &nb:graph[P]) //遍历P的邻接节点
   {
     if(visited[nb]==true)continue; //已经访问过了,则跳过
     //可视化到邻居节点 
     visitor.color(0).speed(1).go(nb).speed(0).wait(0.5);   //角色到达邻居节点 
     visited[nb]=true;          //标记此邻居节点已访问 
     path.push_back(nb);         //存入路径 
     dfs(nb);                   //从这个节点重新开始dfs 
     visited[nb]=false;        //撤销标记 
     path.pop_back();          //节点弹出
     //可视化回退,像时光倒流,红色的血液又流回去了。 
     visitor.color("cyan").speed(1).go(P).speed(0).wait(0.1);     
   } 
}
int main(){        //主功能块 
    g_screen->bgcolor("black");
    pathshower.hide().color("yellow").speed(0).pu().sety(300);
    visitor.scale(0.5).speed(0).color("cyan").pu();
    for(int i=0;i<v.size();i++)
       if(i==2)visitor.go(v[i]).mark(dict[v[i]],30,-18,-18);
       else visitor.go(v[i]).mark(dict[v[i]],30);
    for(int i=0;i<v.size();i++){
    for(int j=i+1;j<v.size();j++)
       visitor.pu().go(v[i]).dot(10,"blue").pd().go(v[j]); 
    }
    visitor.dot(10,"blue").pu(); 
    g_screen->savepng("res/graph.png");
    g_screen->bgpic("res/graph.png");
    visitor.clear();    
    visited[A]=true;
    path.push_back(A);
    visitor.pensize(4).go(A).wait(1).pd();
    dfs(A);
    
    visitor.hide().done();     //完成了
   return 0;    //返回0
}

 

posted on 2026-01-30 15:19  李兴球  阅读(45)  评论(0)    收藏  举报