1,马踏棋盘算法介绍
- 马踏棋盘问题也被称为骑士周游问题
- 将马随机放在国际象棋的8*8的棋盘中的某个格子里,马按照走棋规则(日子)进行移动。要求每个方格只进入一次,走遍64个方格
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5b38442e7d5b062f2efd65d2ae2c6ad6.png)
2,马踏棋盘算法思路分析
- 马踏棋盘算法是对图的深度遍历优先(DFS)的使用,通过递归加回溯实现对问题的解决,同时可使用贪心算法对最终算法进行优化
- 从一点出发,对该点标记为已访问,并寻找该点通过日子走法,下一步可能访问的点坐标的集合
- 如果存在对应的点坐标集合,并且存在点未访问,则按顺序对集合中的未访问坐标点进行递归访问,即重复上一步动作
- 如果存在对应的点坐标集合,但是集合中的所有坐标点已经被访问,此时需要判断走了多少步
- 如果马踏棋盘完美完成,则马应该是走了 8 * 8 = 64步,如果此时马已经走完了64步,则算法正常结束,求出最终解
- 如果此时马走了不到64步,则说明马在走到该坐标时,已经走到了死胡同,则需要回溯,该步无效,对该步的坐标点记录归零
- 通过上面几步递归执行后,已经可以完成马踏棋盘的基本算法,此时可以通过贪心算法进行优化
- 因为算法主要是图的深度遍历优先的使用,则对于马在的当前坐标点,找到下一步可能的坐标点集合时,遍历走到下一步,会继续以当前走到的点为新的节点,寻找下一步可能的坐标点集合
- 此时可以尽量在第一步的时候让深度遍历的工作量更小,即马走的下一个点的下一步可能的坐标点集合更小,这样一步步从最少的访问,等到遍历到多的,其下一步的节点集合也已经被访问了部分,在递归场景下会节省大量时间(使用贪心前20S左右,使用后100MS左右)
- 在算法中,只需要去取得的下一步可能走到坐标点集合进行增序排列,排序标准即是各自对应的下一步可能的坐标点的数量
- 至此,马踏棋盘算法完成
3,代码实现
package com.self.datastructure.algorithm.horse;
import java.awt.Point;
import java.util.*;
public class Horse {
private static int MAX_X;
private static int MAX_Y;
private static boolean flag;
public static void main(String[] args) {
long start = System.currentTimeMillis();
System.out.println("开始进行计算");
MAX_X = 8;
MAX_Y = 8;
int[][] chessBoardArr = new int[MAX_X][MAX_Y];
horse(chessBoardArr, 0, 0, 1);
System.out.println("计算完成...., cost: " + (System.currentTimeMillis() - start));
for (int[] data : chessBoardArr) {
System.out.println(Arrays.toString(data));
}
}
private static void horse(int[][] chessBoardArr, int row, int column, int step) {
chessBoardArr[row][column] = step;
List<Point> lstData = getNextPoint(new Point(row, column));
sort(lstData);
for (Point point : lstData) {
if (chessBoardArr[point.x][point.y] == 0) {
horse(chessBoardArr, point.x, point.y, step + 1);
}
}
if (step < MAX_Y * MAX_X && !flag) {
chessBoardArr[row][column] = 0;
} else {
flag = true;
}
}
private static void sort(List<Point> lstPoint) {
Collections.sort(lstPoint, (o1, o2) -> (getNextPoint(o1).size() - getNextPoint(o2).size()));
}
private static List<Point> getNextPoint(Point point) {
List<Point> lstPoint = new ArrayList<>(10);
Point addPoint = new Point();
if ((addPoint.x = point.x - 2) >= 0 && (addPoint.y = point.y - 1) >= 0) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x - 1) >= 0 && (addPoint.y = point.y - 2) >= 0) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x + 1) < MAX_X && (addPoint.y = point.y - 2) >= 0) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x + 2) < MAX_X && (addPoint.y = point.y - 1) >= 0) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x + 2) < MAX_X && (addPoint.y = point.y + 1) < MAX_Y) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x + 1) < MAX_X && (addPoint.y = point.y + 2) < MAX_Y) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x - 1) >= 0 && (addPoint.y = point.y + 2) < MAX_Y) {
lstPoint.add(new Point(addPoint));
}
if ((addPoint.x = point.x - 2) >= 0 && (addPoint.y = point.y + 1) < MAX_Y) {
lstPoint.add(new Point(addPoint));
}
return lstPoint;
}
}