java调度问题的贪心算法_javascript使用递归回溯算法和贪心算法解决马踏棋盘问题...

马踏棋盘算法介绍和游戏演示

9a8f323ff8d5d9cda964af0f145c31ee.png

1.马踏棋盘算法也被称为骑士周游问题

2.将马随机放在国际象棋的8×8棋盘Board[0~7][0~7]的某个方格中,马按走棋规则(马走日字)进行移动。要求每个方格只进入一次,走遍棋盘上全部64个方格

3.游戏演示: 马踏棋盘_马踏棋盘html5游戏在线玩_4399h5游戏-4399在线玩

马踏棋盘游戏代码实现

1.马踏棋盘问题(骑士周游问题)实际上是图的深度优先搜索(DFS)的应用。

2.如果使用回溯(就是深度优先搜索)来解决,假如马儿踏了53个点,如图:走到了第53个,坐标(1,0),发现已经走到尽头,没办法,那就只能回退了,查看其他的路径,就在棋盘上不停的回溯…… ,思路分析+代码实现

3.分析第一种方式的问题,并使用贪心算法(greedyalgorithm)进行优化。解决马踏棋盘问题.

4.使用前面的游戏来验证算法是否正确。

/**
 *
 *
 骑士周游问题

 1.创建周游问题的解决步骤和思路
 2.将当前位置设置为已经访问,然后根据当前位置,计算马儿还能走哪些位置,
 并放入到一个集合中,最后有8个位置,每走一步,就使用step+1
 3.遍历list中存放的所有位置,看看哪个位置可以走通,如果走通,就回溯
 4.判断马儿是否完成了任务,使用step和应该走的步数比较,如果没有达到数量,
 则表示没有完成任务,将整个棋盘置0

 注意:马儿不同的走法(策略),会得到不同的结果,效率也有影响(优化),
 注意:如果不用贪心算法进行优化,计算步骤会十分庞大导致js线程卡死,
 马踏棋盘问题和迷宫问题不一样,马踏棋盘算法中一个点可能会走很多次,而迷宫问题中一个点只会走一次
 所以马踏棋盘算法的计算量要大的多
 使用贪心算法进行优化
 1.我们获取当前位置,可以走的下一个位置的集合ps
 2.我们需要对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;//马儿初始位置的行,1
let 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);

测试:

2378d1505c86729c92e84503cf0f4c06.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值