有数字的最短路径
Shortest path with figures on board
我在做家庭作业时遇到问题(C++)。我不是在要求完整的解决方案,但朝着正确的方向倾斜可能会有所帮助。:)
我有一个NxN板(最大N = 100)和该板上的1x2数字(立方体)。立方体的一侧涂成红色,另一侧涂成蓝色。立方体的默认位置是棋盘的左上角,蓝色朝上:
B B . .
. . . .
. . . .
. . . .
(4x4 示例,B 代表蓝色)
黑板上可能有石头(障碍物)。我可以用我的身材做出的动作:
- 顺时针旋转 90/180/270 度 您可以围绕立方体
- 的右/左/上/下边缘翻转立方体,更改其"向上颜色"
例如,在默认位置使用右翻转:
. . R R
. . . .
. . . .
. . . .
然后使用旋转 90:
. . R .
. . R .
. . . .
. . . .
然后使用左翻转:
. B . .
. B . .
. . . .
. . . .
当然,旋转或翻转时,您不能落在石头上。所以,问题是 - 对于电路板的任何给定配置(图形位置和石头位置),编写一个程序,该程序将在默认位置"将立方体带回家"(蓝色面朝上!使用最少的移动次数,如果可能,则返回 1,如果不可能,则返回 0。
我觉得这个问题很有趣,但我不得不承认我对它有点困惑。尤其是蓝色侧面/红色侧面部分。我真的不知道如何"翻译"那些可以用通常的最短路径算法语言使用的动作(我从来没有使用过这些)。因此,如果您能给出的每一条建议,我将不胜感激!:)
首先,由于要求您找到确切的最佳路径,我将使用Dijksta的算法。
对于此算法,您需要:
- 一个给出下一个的函数可能的移动。
- 告诉您仓位是否已经存在的函数访问。
- 告诉您每条路径的总成本的函数。
- 当然还有一个功能,告诉你什么时候到达决赛位置
给定初始位置,您的立方体可以恰好达到 7 个新位置。很容易选择哪些是可能的。
G 只是您到目前为止所做的移动次数 + 1 表示下一步:)
我会使用哈希表来跟踪访问的位置。(这可能是最难写的函数),但你现在不需要过度思考。一个简单的向量和逐项比较就可以了。您可以在代码运行后对其进行优化。
最后,您需要检查立方体是否处于其初始位置,蓝色面朝上。
您可以将每个可能的 1x2 块和颜色(红色或蓝色)组合解释为顶点并作为边移动。如果有可能在一次移动中从其他组合到达特定的 1x2 块和颜色组合(顶点),那么这两个组合之间存在连接(边缘)。然后,您必须在结果图表中找到给定配置和"主页"配置之间的最短路径(可能是广度优先搜索,因为无论您执行什么移动,移动的成本都是相同的)。
如果想走得更远,您可以使用高级图形搜索算法,该算法在图形遍历期间使用启发式(启发式是到达目的地所需的最小移动量,假设黑板上没有障碍物)。例如,您可以使用 A* 算法。
在处理此类问题时,首先要做的是找到问题状态的表示。在这种情况下,您需要:
- 两个整数,代表图形的左上角位置
- 一个表示图形颜色的布尔值(红色/蓝色)
- 一个表示图形方向的布尔值(水平/垂直)
如果您熟悉位掩码,则应仅使用 32 位整数来执行此操作(8 位表示 x 位置,8 位表示 y 位置,2 位用于其余位置)。这样,您就不需要实现比较运算符。或你用这 3 个信息定义了一个简单的结构(称之为 state
),并对此进行了严格排序的比较(这只需要将state
放入std::set
中。
在此之后,您可以使用BFS解决此问题。
为此,您需要:
- 一种
std::map<state,state>
,用于在键中存储您已经访问过的位置,以及您在值中来自的位置(如果您可以使用 c++11 并使用位掩码存储您的状态,请将map
替换为unordered_map
) - 推送和弹出要处理的状态的
std::queue<state>
。 - 一些代码来确定从给定状态可到达的每个可能状态(即实现所有可能的移动,照顾电路板尺寸)
伪代码:
map<state,state> visited;
queue<state> to_be_processed;
visited.insert( initial_state,initial_state); //you are not coming from anywhere
to_be_processed.push ( initial_state);
while(!to_be_processed.empty()) {
state cur = to_be_processed.pop();
if ( cur == end_state) //you are done
{
//to get the path from initial_state to end_state you have just to walk visited in the inverse order.
return 1;
}
for ( i = every possible state reachable from cur) {
if (visited.count(i) != 0) continue; //already visited
to_be_processed.push(i);
visited.insert(i,cur); //i has been visited, and you reached i from cur
}
}
return 0; //if you get here, no way
障碍物的存在使问题更难编码,但在概念上没有什么不同。
请注意,在这种情况下,BFS 之所以有效,是因为您从一个州到另一个州支付的费用始终相同。
- 内存效率表示最短路径的方法?
- 用于查找网格中最短路径的算法
- 查找最短路径算法
- BFS 打印最短路径
- 使用 Dijkstra 算法跟踪两个节点之间的最短路径
- 使用C++具有两个数字的最短路径算法.(C++)
- 使用迭代深度优先搜索算法的未加权图的最短路径
- 如何仅在 2 个节点之间获取最短路径,给定邻接列表有向图?
- 如何使用贝尔曼-福特算法返回所有具有捆绑重量的最短路径?
- 使用优先级队列查找所有与 Dijkstra 相同的最短路径
- 尝试在图形中查找最短路径时的无限循环
- C++计算有向图中的最短路径
- 使用BFS存储和打印最短路径
- 如何制作由原始图形的最短路径边组成的新图形
- 有没有一种方法可以使用弗洛伊德-沃歇尔算法给出最短路径,其中存在负权重循环而不允许重叠边缘?
- 加权图的开始和结束的最短路径
- 使 c++11 Dijkstra 实现返回最短路径
- 弗洛伊德最短路径算法C++
- 有数字的最短路径
- 如何找到一个数字在两个方向上的最短路径