Algorithm 如何解决这个需要最少步骤才能到达矩阵末尾的问题?

Algorithm 如何解决这个需要最少步骤才能到达矩阵末尾的问题?,algorithm,matrix,depth-first-search,breadth-first-search,Algorithm,Matrix,Depth First Search,Breadth First Search,给定一个包含每个元素初始状态的矩阵,找出从左上到右下的最小步数 条件: 任何元素的初始状态将随机为北、东、南或西。 在每一步中,我们要么不能移动到任何地方,要么朝着元素当前状态的方向移动(当然,我们永远不会离开矩阵) 任何步骤都会同时改变矩阵中所有元素的状态。状态以顺时针循环的方式变化,即从N->e->S->W。即使我们不在一个步骤中移动,状态也会发生变化。一个重要的观察结果是,矩阵有4个不同的“版本”:每4个步骤的倍数,矩阵的内容将完全相同 您可以将这4个矩阵想象为第三维(Z方向),其中Z可以

给定一个包含每个元素初始状态的矩阵,找出从左上到右下的最小步数

条件:

任何元素的初始状态将随机为北、东、南或西。 在每一步中,我们要么不能移动到任何地方,要么朝着元素当前状态的方向移动(当然,我们永远不会离开矩阵)
任何步骤都会同时改变矩阵中所有元素的状态。状态以顺时针循环的方式变化,即从N->e->S->W。即使我们不在一个步骤中移动,状态也会发生变化。一个重要的观察结果是,矩阵有4个不同的“版本”:每4个步骤的倍数,矩阵的内容将完全相同

您可以将这4个矩阵想象为第三维(Z方向),其中Z可以是0、1、2或3。将其想象为一个3D阵列,其中4 x 2D阵列相互层叠

在3D矩阵中,“旋转”值的魔力消失了:这4个矩阵中的每一个现在都是静态的

现在的一个步骤是:

  • 沿当前单元格中的内容指示的方向移动,因此X或Y发生变化,或
  • X和Y保持不变的移动
…但在这两种情况下,Z都变成(Z+1)%4

目标单元格现在实际上是一组4个单元格,因为在到达右下角的那一刻,Z是什么并不重要

如果您构建这个(未加权、定向)图,您可以实现一个简单的BFS搜索。问题解决了

实施 我想我会为以下示例输入矩阵制作一个小动画:

[
    [2, 0, 0, 2, 1, 0, 3],
    [0, 0, 0, 2, 0, 0, 1],
    [3, 2, 0, 3, 3, 3, 0],
]
这些数字表示当前可能的方向:0=北,1=东,2=南,3=西

该算法由两个函数组成。一种是节点类的方法,
shortestPathTo
,它实现了从一个节点到一组目标节点的通用BFS搜索。第二个函数,
createGraph
,将如上所述将输入矩阵转换为图形。创建此图后,可以在左上角节点上调用
shortestPathTo
方法。它返回一个
路径
,一个要访问的节点数组

该路径用于制作动画,这是代码的下半部分所处理的。这一部分与算法没有什么关系,所以您可以忽略它

类节点{//泛型节点类;不依赖于特定问题
构造函数(值、标签){
这个值=值;
this.label=标签;
this.neights=[];
}
添加到(邻居){
这个。邻居。推(邻居);
}
最短路径(目标){
目标=新集合(目标);//将数组转换为集合
//标准BFS
让queue=[this];//从当前节点开始
让comingFrom=新地图;
comingFrom.set(此为空);
while(queue.length){
让节点=queue.shift();
如果(targets.has(node)){//Found!
let path=[];//从反向链表生成路径
while(节点){
路径推送(节点);
node=comingFrom.get(节点);
}
返回路径:reverse();
}
for(设node.nextNode的nextNode){
如果(!comingFrom.has(nextNode)){
comingFrom.set(下一个节点,节点);
queue.push(nextNode);
}
}
}
return[];//无法到达目标节点
}
}
函数createGraph(矩阵){
//将矩阵及其移动规则转换为有向图
常量numCols=矩阵[0]。长度;
const numRows=矩阵长度;
常数numNodes=numRows*numCols*4;/| Y |*| X |*| Z|
//创建节点
常量节点=[];
for(设y=0;y0)dj=-numCols*4;
如果(dir==1&&x+10)dj=-4;
if(dj)节点。加到(节点[j+dj]);
}
//返回图形的节点
返回节点;
}
//样本矩阵
设矩阵=[
[2, 0, 0, 2, 1, 0, 3],
[0, 0, 0, 2, 0, 0, 1],
[3, 2, 0, 3, 3, 3, 0],
];
//计算解决方案:
常量节点=createGraph(矩阵);
常量路径=节点[0]。最短路径到(nodes.slice(-4));
//path现在具有要访问的节点序列。
//此代码段的I/O处理
常数大小=26;
constpaint=()=>newpromise(解析=>requestAnimationFrame(解析));
函数drawSquare(ctx、x、y、角度){
ctx.rect(x*尺寸+0.5,y*尺寸+0.5,尺寸,尺寸);
ctx.stroke();
ctx.beginPath();
角度=(270+角度)*Math.PI/180;
x=(x+0.5)*尺寸;
y=(y+0.5)*尺寸;
ctx.moveTo(x+0.5,y+0.5);
ctx.lineTo(x+数学余弦(角度)*尺寸*0.4+0.5,y+数学余弦(角度)*尺寸*0.4+0.5);
ctx.stroke();
}
功能牵引杆(ctx、x、y){
x=(x+0.5)*尺寸;
y=(y+0.5)*尺寸;
ctx.beginPath();
弧(x,y,大小*0.2,0,2*Math.PI);
ctx.fillStyle=“红色”;
ctx.fill();
}
异步函数绘制(ctx,矩阵,时间=0,角度=0,curX=0,curY=0){
等待油漆();
时间=时间%4;
clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
for(设y=0;y