该算法的简单版本的想法如下:
- 定义一个顶点列表(你可以停留的地方)和边(你可以走)
- 每个顶点都有一个连接到其他顶点的边列表
- 对于每个边缘存储步行长度
- 对于每个顶点存储一个 1000000000 的字段,其含义是“步行到这里需要多长时间”
- 创建仅使用起点初始化的“活动”顶点列表
- 将起始顶点的步行距离字段设置为 0(你在这里)
现在搜索算法进行如下
- 从“活动列表”中选择最低的(a)顶点
walk_distance
并将其从列表中删除
- 如果顶点是你完成的目的地。
other_vertex
否则,对于该顶点中的每条边,计算到as的步行距离
new_dist = vertex.walk_distance + edge.length
检查新距离是否短于other_vertex.walk_distance
,在这种情况下更新other_vertex.walk_distance
为新值,如果该顶点不存在,则将该顶点放入“活动列表”中。
- 从 1 重复
如果您用完活动列表中的节点并且从未处理过目标顶点,则意味着无法从起始顶点到达目标顶点。
对于 C++ 中的数据结构,我会使用类似的东西
struct Vertex {
double walk_distance;
std::vector<struct Edge *> edges;
...
};
struct Edge {
double length;
Vertex *a, *b;
...
void connect(Vertex *va, Vertex *vb) {
a = va; b = vb;
va->push_back(this); vb->push_back(this);
}
...
};
然后从输入中我知道,对于n
级别,需要2*n
顶点(每个楼层的左侧和右侧)和2*(n-1) + n
边缘(每个楼梯一个,每个楼层步行一个)。
对于除最后一层外的每一层,您需要构建三个边缘,对于最后一层只有一个。
我还会先在向量中分配所有边和顶点,然后再修复指针(构建后设置是一种反模式,但这里是为了避免重新分配问题并且仍然保持非常简单)。
int n = number_of_levels;
std::vector<Vertex> vertices(2*n);
std::vector<Edge> edges(2*(n-1) + n);
for (int i=0; i<n-1; i++) {
Vertex& left = &vertices[i*2];
Vertex& right = &vertices[i*2 + 1];
Vertex& next_left = &vertices[(i+1)*2];
Vertex& next_right = &vertices[(i+1)*2 + 1];
Edge& dl_ur = &edges[i*3]; // down-left to up-right stair
Edge& dr_ul = &edges[i*3+1]; // down-right to up-left stair
Edge& floor = &edges[i*3+2];
dl_ur.connect(left, next_right);
dr_ul.connect(right, next_left);
floor.connect(left, right);
}
// Last floor
edges.back().connect(&vertex[2*n-2], &vertex[2*n-1]);
注意:未经测试的代码
编辑
当然,这个算法可以解决一个更普遍的问题,即顶点和边的集合是任意的(但长度是非负的)。
对于非常具体的问题,可以使用更简单的算法,它甚至不需要任何数据结构,而是可以在读取输入时动态计算结果。
#include <iostream>
#include <algorithm>
int main(int argc, const char *argv[]) {
int n; std::cin >> n;
int l=0, r=1000000000;
while (--n > 0) {
int a, b, c; std::cin >> a >> b >> c;
int L = std::min(r+c, l+b+c);
int R = std::min(r+b+a, l+a);
l=L; r=R;
}
int b; std::cin >> b;
std::cout << std::min(r, l+b) << std::endl;
return 0;
}
这个解决方案的想法很简单:
l
变量是walk_distance
地板左侧的
r
变量是walk_distance
右侧的
算法:
我们初始化l=0
,r=1000000000
因为我们在左侧
对于所有中间步骤,我们读取三个距离:
a
是从左下到右上楼梯的长度
b
是地板的长度
c
是从右下到左上楼梯的长度
我们计算walk_distance
下一层的左侧和右侧
L
r+c
是和之间的最小值l+b+c
(要么我们从右侧开始,要么我们先从左侧开始)
R
l+a
是和之间的最小值r+b+a
(要么我们从左边开始,要么我们从右边开始,然后先穿过地板)
对于最后一步,我们只需要通过穿过最后一层来选择r
从那里到那里的最小值l