P4366 [Code+#4]最短路

文章讨论了一种优化方法来解决图的单源最短路问题。在一层完全图和一层给定图中,通过将边权(u⊕v)二进制拆位,只保留从每个点出发,边权为2^k的边,以此降低复杂度,避免暴力建边的n^2操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P4366 [Code+#4]最短路

一个图有两层:

  • 一层完全图,每对 \(u\)\(v\) 间都有一条边权为 \(u \oplus v\) 的边。
  • 一层给定图,边信息完全给定。这层图的边数 \(m \le 5 \times 10^5\)

求单源最短路。\(n \le 10^5\)


暴力建边 \(n^2\) 不可取,所以优化建图。

第一层是完全图,第二层是直接给定边的图。对第一层优化,然后再加第二层。

想到把 \((u, v, u \oplus v)\) 拆成 \(u \rightsquigarrow v\) 路径的形式,使得路径权值和 \(w\) 满足 \(w \le u \oplus v\)

可以猜想上面这个其实就是 \(w = u \oplus v\)

然后发现可以把 \(u \oplus v\) 二进制拆位,于是可以只保留从每个点开始,边权为 \(2^k\) 的边。

端点范围细节:https://www.luogu.com.cn/discuss/585050

### 使用 EasyX 图形库实现计算两点间最短路径 为了实现在迷宫中找到并展示两点间的最短路径,可以采用 A* 算法来寻找最优解,并通过 EasyX 图形库可视化这一过程。以下是具体方法: #### 1. 安装与配置 EasyX 库 确保已经成功安装了 Code::Blocks 和 MinGW 编译器,并按照官方文档完成 EasyX 的环境搭建[^2]。 #### 2. 初始化图形窗口 创建一个新的控制台项目,在 `main.cpp` 文件顶部加入如下头文件声明: ```cpp #include <graphics.h> #include <conio.h> ``` 接着初始化绘图区域大小以及背景颜色设置: ```cpp int main() { initgraph(800, 600); // 创建一个宽800高600像素的窗口 setbkcolor(WHITE); cleardevice(); } ``` #### 3. 构建迷宫结构体定义 定义表示节点的数据类型 Node 及其成员变量用于存储坐标位置 (x,y),父节点指针 parent 以便回溯路径,gScore 表示起点到达该点的成本代价 fScore 则是估计总成本: ```cpp struct Node { int x; int y; double gScore; // 已知距离起始点的实际开销 double fScore; // 预估剩余至终点的距离加上实际走过的路程长度之和 }; ``` #### 4. 实现 A* 寻路逻辑 编写核心算法部分,包括启发式评估函数 heuristic_cost_estimate(), 获取邻居列表 get_neighbors() ,判断是否达到目标 is_goal_reached() 函数等辅助功能;最后调用 astar_search() 来执行整个搜索流程。 ```cpp double heuristic_cost_estimate(Node start, Node goal){ return abs(start.x-goal.x)+abs(start.y-goal.y); } std::vector<Node> get_neighbors(const std::unordered_map<int,std::pair<int,int>>& gridMap ,Node current){ ... } bool is_goal_reached(Node node, Node end){ return node.x==end.x && node.y==end.y ; } void drawPath(std::list<Node>& path){ for(auto& p :path){ circle(p.x,p.y,5); Sleep(100); } } std::optional<std::list<Node>> astar_search(){ ... } ``` #### 5. 绘制迷宫地图及标记起点终点 使用矩形绘制墙壁障碍物,圆形代表可通行空间内的各个格子单元。同时指定出发地和目的地的位置信息作为输入参数传递给寻径引擎。 ```cpp // 假设有这样一个简单的二维数组描述了一个小型迷宫布局 const char maze[][9]={ "#########", "#S......#", "#.#.#####", "#...#.E..", "######...", ".#.......","....#....","#.....#..","#........" }; for(int i=0;i<7;++i) { for(int j=0;j<9;++j) { if(maze[i][j]=='#') rectangle(j*50,i*50,j*50+50,i*50+50); else if(maze[i][j]=='S'){ fillcircle((j)*50+25,(i)*50+25,10,COLOR(255,0,0)); start={j,i}; } else if(maze[i][j]=='E') { fillcircle((j)*50+25,(i)*50+25,10,COLOR(0,255,0)); target={j,i};} else{ fillcircle((j)*50+25,(i)*50+25,10,COLOR(0,0,255)); } } } ``` #### 6. 执行路径规划并显示结果 当一切准备就绪后,启动 A* 搜索进程获取最佳路线方案,随后借助之前提到的 drawPath 方法逐步描绘出完整的行走轨迹直至抵达最终目的为止。 ```cpp if(auto result =astar_search();result.has_value()){ auto &path=*result; drawPath(path); }else{ printf("No valid path found!\n"); } getch(); closegraph(); return 0; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值