马踏棋盘游戏代码实现
马踏棋盘问题(骑士周游问题)实际上是图的深度优先搜索(DFS)的应用。
如果使用回溯(就是深度优先搜索)来解决,假如马儿踏了53个点,如图:走到了第53个,坐标(1,0),发现已经走到尽头,没办法,那就只能回退了,查看其他的路径,就在棋盘上不停的回溯…… ,思路分析+代码实现
分析第一种方式的问题,并使用贪心算法(greedyalgorithm)进行优化。解决马踏棋盘问题.
使用前面的游戏来验证算法是否正确。
骑士周游问题的解决步骤和思路
- 创建棋盘 chessBoard , 是一个二维数组
- 将当前位置设置为已经访问,然后根据当前位置,计算马儿还能走哪些位置,并放入到一个集合中(ArrayList), 最多有8个位置, 每走一步,就使用step+1
- 遍历ArrayList中存放的所有位置,看看哪个可以走通 , 如果走通,就继续,走不通,就回溯.
- 判断马儿是否完成了任务,使用 step 和应该走的步数比较 , 如果没有达到数量,则表示没有完成任务,将整个棋盘置0
注意:马儿不同的走法(策略),会得到不同的结果,效率也会有影响(优化)
//创建一个Point
Point p1 = new Point();
if((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y -1) >= 0) {
ps.add(new Point(p1));
}
使用贪心算法对原来的算法优化
1。 我们获取当前位置,可以走的下一个位置的集合
//获取当前位置可以走的下一个位置的集合
ArrayList ps = next(new Point(column, row));
2. 我们需要对 ps 中所有的Point 的下一步的所有集合的数目,进行非递减排序,就ok ,
9, 7, 6, 5, 3, 2 , 1 //递减排序
1, 2, 3, 4,5,6, 10, //递增排序
1, 2, 2, 2, 3,3, 4, 5, 6 // 非递减
9, 7, 6,6, 6, 5,5, 3, 2 , 1 //非递增
public class HorseChessBoard {
public static final int X = 8;
public static final int Y = 8;
public static boolean[] visited = new boolean[X * Y];
public static boolean finished = false;
public static void main(String[] args) {
long start = System.currentTimeMillis();
int[][] chessBoard = new int[X][Y];
traversalChessBoard(chessBoard, 0, 0, 1);
System.out.println("cost" + (System.currentTimeMillis() - start) + "ms");
for (int i = 0; i < chessBoard.length; i++) {
System.out.println(Arrays.toString(chessBoard[i]));
}
}
/**
* 马踏棋盘算法
*
* @param chessBoard 棋盘
* @param row 行
* @param column 列
* @param step 步
*/
public static void traversalChessBoard(int[][] chessBoard, int row, int column, int step) {
chessBoard[row][column] = step;
// 行列都是从0开始,所以+column时不用减一
visited[Y * row + column] = true;
// 列相当于point的x,row相当于point的y
ArrayList<Point> next = next(new Point(column, row));
// 此处使用贪心算法,优先走下一步可选路径少的,这样可以减少回溯的步骤,对下一步的路径个数进行非递减排序
next.sort((o1, o2) -> {
int size1 = next(o1).size();
int size2 = next(o2).size();
if (size1 < size2) {
return -1;
} else if (size1 == size2) {
return 0;
} else {
return 1;
}
});
while (!next.isEmpty()) {
Point p = next.remove(0);
// 改点没被访问
if (!visited[p.y * Y + p.x]) {
// 递归访问该点
traversalChessBoard(chessBoard, p.y, p.x, step + 1);
}
}
// 判断马儿是否完成了任务,使用 step 和应该走的步数比较 ,
// 如果没有达到数量,则表示没有完成任务,将整个棋盘置0
// 说明: step < X * Y 成立的情况有两种
// 1. 棋盘到目前位置,仍然没有走完
// 2. 棋盘处于一个回溯过程
if (step < X * Y && !finished) {
chessBoard[row][column] = 0;
visited[row * Y + column] = false;
} else {
finished = true;
}
}
/**
* 获取下一步可走路径的集合
*
* @param point
* @return
*/
public static ArrayList<Point> next(Point point) {
ArrayList<Point> list = new ArrayList<>();
Point p1 = new Point();
// 5号位
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y - 1) >= 0) {
list.add(new Point(p1));
}
// 6号位
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y - 2) >= 0) {
list.add(new Point(p1));
}
// 7号位
if ((p1.x = point.x + 1) < X && (p1.y = point.y - 2) >= 0) {
list.add(new Point(p1));
}
// 0号位
if ((p1.x = point.x + 2) < X && (p1.y = point.y - 1) >= 0) {
list.add(new Point(p1));
}
// 1号位
if ((p1.x = point.x + 2) < X && (p1.y = point.y + 1) < Y) {
list.add(new Point(p1));
}
// 2号位
if ((p1.x = point.x + 1) < X && (p1.y = point.y + 2) < Y) {
list.add(new Point(p1));
}
// 3号位
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y + 2) < Y) {
list.add(new Point(p1));
}
// 4号位
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y + 1) < Y) {
list.add(new Point(p1));
}
return list;
}
}