马踏棋盘算法

介绍

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

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

3.基本思想:图的深度优先搜索 + 贪心算法(优化)

 

步骤

1.创建一个二维数组代表棋盘

2.将当前位置设置为已经访问,把当前马在棋盘的位置标记为第几步(step),然后根据当前位置,计算马还能走哪些位置,并放入ArrayList,最多有8个位置

3.获取到ArrayList后,用贪心算法优化

4.遍历ArrayList中存放的所有位置,判断哪个位置可以走通,如果走通,就继续,走不通,就回溯

5.判断是否走完整个棋盘,使用step和应该走的步数比较,如果没有达到数量,则表示没有完成任务,并将整个棋盘置0

 

贪心算法优化ArrayList

1.基本思想:根据当前这个一步的所有的下一步的选择位置,进行非递减(即不严格递增)排序, 减少回溯的次数

步骤

(1)传入Comparotor,重写ArrayList的sort方法

(2)获取ArrayList所有位置的通路个数,按非递减排序

(3)即当前位置的下一步的下一步通路最少,就优先选择

 

代码实现

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class KnightTravel {//骑士周游问题
    public int row;//棋盘的行数
    public int column;//棋盘的列数
    public int[][] chessboard;//棋盘
    public boolean[][] visited;//标记棋盘的各个位置是否被访问过,true:已访问
    public boolean finished;//标记是否棋盘的所有位置都被访问,若为true,表示算法计算成功
    public int step = 1;//初始为第一步

    public static void main(String[] args) {
        KnightTravel knight = new KnightTravel(8, 8);
        long start = System.currentTimeMillis();
        knight.travel(knight.chessboard, 0, 0, knight.step);
        long end = System.currentTimeMillis();
        System.out.println("共耗时: " + (end - start) + " 毫秒");
        knight.result();
    }

    public KnightTravel(int row, int column) {
        this.row = row;
        this.column = column;
        this.chessboard = new int[row][column];
        this.visited = new boolean[row][column];
    }

    public void result() {//打印算法结果
        for (int[] row : chessboard) {
            System.out.println(Arrays.toString(row));
        }
    }

    //马踏棋盘算法
    //chessboard:棋盘,row:马儿当前的位置的行,从0开始,column:马儿当前的位置的列 ,从0开始,step:第几步,初始位置是第1步
    public void travel(int[][] chessboard, int row, int column, int step) {
        chessboard[row][column] = step;
        visited[row][column] = true; //标记该位置已经访问
        //获取当前位置可以走的下一个位置的集合
        ArrayList<Point> access = next(new Point(column, row));
        sort(access);//对access进行非递减排序
        while (!access.isEmpty()) {
            Point next = access.remove(0);//取出下一个可以走的位置
            if (!visited[next.y][next.x]) {//判断该点是否已经访问过
                travel(chessboard, next.y, next.x, step + 1);
            }
        }
        if (step < this.row * this.column && !finished) {
            //无路可走且未走完,就回溯到上一位置
            chessboard[row][column] = 0;
            visited[row][column] = false;
        } else {
            //成功走完时,finished是防止回溯时将最优解覆盖掉
            finished = true;
        }

    }

    //根据当前位置(curPoint),计算马还能走哪些位置(point),并放入一个集合中(ArrayList), 最多有8个位置
    public ArrayList<Point> next(Point curPoint) {
        //储存马在当前位置的通路
        ArrayList<Point> access = new ArrayList<>();
        //Point对象中,属性x代表列,属性y代表行
        Point point = new Point();
        //以下操作,判断马的8个方向是否可行,并记录通路位置,但不记录该位置是否已访问
        if ((point.x = curPoint.x - 2) >= 0 && (point.y = curPoint.y - 1) >= 0) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x - 1) >= 0 && (point.y = curPoint.y - 2) >= 0) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x + 1) < column && (point.y = curPoint.y - 2) >= 0) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x + 2) < column && (point.y = curPoint.y - 1) >= 0) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x + 2) < column && (point.y = curPoint.y + 1) < row) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x + 1) < column && (point.y = curPoint.y + 2) < row) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x - 1) >= 0 && (point.y = curPoint.y + 2) < row) {
            access.add(new Point(point));
        }
        if ((point.x = curPoint.x - 2) >= 0 && (point.y = curPoint.y + 1) < row) {
            access.add(new Point(point));
        }
        return access;
    }

    //根据当前这个一步的所有的下一步的选择位置,进行非递减(不严格递增)排序, 减少回溯的次数
    public void sort(ArrayList<Point> access) {
        access.sort(new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                int count1 = next(o1).size();
                int count2 = next(o2).size();
                if (count1 < count2) {
                    return -1;
                } else if (count1 == count2) {
                    return 0;
                } else {
                    return 1;
                }
            }
        });
    }
}

 

posted @   半条咸鱼  阅读(325)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示