/****骑士周游问题1.创建周游问题的解决步骤和思路2.将当前位置设置为已经访问,然后根据当前位置,计算马儿还能走哪些位置,并放入到一个集合中,最后有8个位置,每走一步,就使用step+13.遍历list中存放的所有位置,看看哪个位置可以走通,如果走通,就回溯4.判断马儿是否完成了任务,使用step和应该走的步数比较,如果没有达到数量,则表示没有完成任务,将整个棋盘置0注意:马儿不同的走法(策略),会得到不同的结果,效率也有影响(优化),注意:如果不用贪心算法进行优化,计算步骤会十分庞大导致js线程卡死,马踏棋盘问题和迷宫问题不一样,马踏棋盘算法中一个点可能会走很多次,而迷宫问题中一个点只会走一次所以马踏棋盘算法的计算量要大的多使用贪心算法进行优化1.我们获取当前位置,可以走的下一个位置的集合ps2.我们需要对ps中所有的point下一步的所有集合的数目,进行非递减排序,其实就是递增优化的原因,我们优先选择所有的下一个位置的选择的位置最小的那个,可以减少回溯假设我们每一个马儿位置,有n个位置可以继续走,我们此时不知道这n个位置能否成功走完棋盘,那么设每个位置的完成概率是相等的p(n*p=1),但是我们可以确定每个位置的完成时间(完成时间=成功时间*成功概率+失败时间*失败概率,成功时间,成功概率和失败概率是相等的,但是失败时间不等)大小,n个位置的完成时间,依次为t1,t2,...tn,.....,此时我们可以看到走n1和n2位置成功与走n3和n4的总成功率是相等的,但是总完成时间是不等,我们为了效率,在获取相同成功率的情况下,总完成时间越短则效率越高***/
class HorseChessboard {
x;//棋盘的列数 y;//棋盘的行数 visited = [];//创建一个数组,标记棋盘的各个位置是否被访问过 //使用一个属性,标记是否棋盘的所有位置都被访问过 finished;
constructor() {
}
//我们需要对ps中所有的point下一步的所有集合的数目,进行非递减排序,其实就是递增 sort = (o1, o2) => {
//获取到o1的下一步的所有位置个数 let count1 = this.next(o1).length;
//获取到o2的下一步的所有位置个数 let count2 = this.next(o2).length;
if (count1 < count2) {
return -1;
} else if (count1 == count2) {
return 0;
} else {
return 1;
}
}
/*** 完成骑士周游问题的算法* @param {棋盘} chessboard* @param {马儿当前位置的行,初始为0} row* @param {马儿当前位置的列,初始为0} col* @param {第第几步,初始位置为1} step*/
traversalChessboard(chessboard, row, col, step) {
chessboard[row][col] = step;
this.visited[row * this.x + col] = true;//标记为已访问 //获取当前位置可以走的下一个位置的集合 let ps = this.next(new Point(col, row));
//贪心算法优化,对ps中所有的point下一步的所有集合的数目,进行非递减排序,其实就是递增 ps.sort(this.sort);
//遍历ps while (ps.length > 0) {
//取出下一个可以走的位置 let p = ps.shift();
//判断该点是否已经访问过 if (!this.visited[p.y * this.x + p.x]) {
//还没访问过 this.traversalChessboard(chessboard, p.y, p.x, step + 1);
}
}
//判断马儿是否完成了任务 //如果没有达到数量,则表示没有完成任务,将整个棋盘置0 //说明:step < this.x * this.y成立的情况有两种 //1.棋盘到目前位置,棋盘没有走完 //2。棋盘处于一个回溯过程 if (step < this.x * this.y && !this.finished) {
chessboard[row][col] = 0;
this.visited[row * this.x + col] = false;
} else {
this.finished = true;
}
}
/*** 根据当前位置,计算马儿还能走哪些位置,最多有8个位置* @param {*} curPoint*/
next(curPoint) {
let list = [];
let p1 = new Point();
//1.表示马儿可以走左二上一这个位置 if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y - 1) >= 0) {
list.push(new Point(p1.x, p1.y));
}
//2.判断马儿可以走左一上二 if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 2) >= 0) {
list.push(new Point(p1.x, p1.y));
}
//3.判断马儿可以走右一上二 if ((p1.x = curPoint.x + 1) < this.x && (p1.y = curPoint.y - 2) >= 0) {
list.push(new Point(p1.x, p1.y));
}
//4.表示马儿可以走右二上一 if ((p1.x = curPoint.x + 2) < this.x && (p1.y = curPoint.y - 1) >= 0) {
list.push(new Point(p1.x, p1.y));
}
//5.表示马儿可以走右二下一 if ((p1.x = curPoint.x + 2) < this.x && (p1.y = curPoint.y + 1) < this.y) {
list.push(new Point(p1.x, p1.y));
}
//6.表示马儿可以走右一下二 if ((p1.x = curPoint.x + 1) < this.x && (p1.y = curPoint.y + 2) < this.y) {
list.push(new Point(p1.x, p1.y));
}
//7.表示马儿可以走左一下二 if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y + 2) < this.y) {
list.push(new Point(p1.x, p1.y));
}
//8.表示马儿可以走右二下一 if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y + 1) < this.y) {
list.push(new Point(p1.x, p1.y));
}
return list;
}
}
//点坐标class Point {
x;
y;
constructor(x, y) {
this.x = x;
this.y = y;
}
}
//测试骑士周游算法let x = 8, y = 8;
let test = new HorseChessboard();
test.x = x;
test.y = y;
let row = 1;//马儿初始位置的行,1let column = 1;//马儿初始位置的列,1//创建棋盘let chessboard = new Array(y);
for (let i = 0; i < y; i++) {
chessboard[i] = new Array(x).fill(0);
}
test.visited = new Array(x * y).fill(false);
test.traversalChessboard(chessboard, row - 1, column - 1, 1);
//输出棋盘console.log('棋盘走的步骤:', chessboard);
console.log(test);