骑士周游回溯算法
基本介绍
马踏棋盘问题是旅行商问题(TSP)或哈密顿回路问题(HCP)的一个特例。在 8×8 的国际象棋棋盘上,用一个马按照马步跳遍整个棋盘,要求每个格子都只跳到一次,最后回到出发点。这是一个 NP问题,通常采用回溯法或启发式搜索类算法求解。在 9×10 的中国象棋棋盘上也可以实现马步遍历。
思路
可以编写一个方法获得起始位置可以走的位置(最多8个),然后回溯算法
代码
package com.fly.horse;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class HorseChessboard {
public static void main(String[] args) {
X = 6;
Y = 6;
int row = 3;
int column = 4;
int[][] chessboard = new int[X][Y];
visited = new boolean[X * Y];
traversalChessboard(chessboard,row - 1,column - 1,1);
for(int[] rows : chessboard) {
for(int step: rows) {
System.out.print(step + "\t");
}
System.out.println();
}
}
private static int X; //棋盘的列数
private static int Y; //棋盘的行数
private static boolean[] visited; //是否被访问过
private static boolean finished; //是否成功
/**
* 根据当前位置(Point对象),计算马儿还能走哪些位置(Point),并放入到一个集合中(ArrayList)
* @param curPoint 起始位置的对象
* @return 起始位置可以走的点的对象集合
*/
public static List<Point> next(Point curPoint) {
List<Point> points = new ArrayList<>();
Point point1 = new Point();
//表示马儿可以走5这个位置
if((point1.x = curPoint.x - 2) >= 0 && (point1.y = curPoint.y -1) >= 0) {
points.add(new Point(point1));
}
//判断马儿可以走6这个位置
if((point1.x = curPoint.x - 1) >=0 && (point1.y=curPoint.y-2)>=0) {
points.add(new Point(point1));
}
//判断马儿可以走7这个位置
if ((point1.x = curPoint.x + 1) < X && (point1.y = curPoint.y - 2) >= 0) {
points.add(new Point(point1));
}
//判断马儿可以走0这个位置
if ((point1.x = curPoint.x + 2) < X && (point1.y = curPoint.y - 1) >= 0) {
points.add(new Point(point1));
}
//判断马儿可以走1这个位置
if ((point1.x = curPoint.x + 2) < X && (point1.y = curPoint.y + 1) < Y) {
points.add(new Point(point1));
}
//判断马儿可以走2这个位置
if ((point1.x = curPoint.x + 1) < X && (point1.y = curPoint.y + 2) < Y) {
points.add(new Point(point1));
}
//判断马儿可以走3这个位置
if ((point1.x = curPoint.x - 1) >= 0 && (point1.y = curPoint.y + 2) < Y) {
points.add(new Point(point1));
}
//判断马儿可以走4这个位置
if ((point1.x = curPoint.x - 2) >= 0 && (point1.y = curPoint.y + 1) < Y) {
points.add(new Point(point1));
}
return points;
}
/**
* 根据这个位置的下一步的所有下一步的可以选择的位置,进行非递减排序, 减少回溯的次数
* @param points 一个位置所有可以走的位置的对象集合
*/
public static void sort(List<Point> points) {
points.sort((o1, o2) -> {
int count1 = next(o1).size();
int count2 = next(o2).size();
if (count1 < count2) {
return -1;
} else if (count1 == count2) {
return 0;
} else {
return 0;
}
});
}
/**
* @param chessboard 棋盘对象
* @param row 起始位置的行,从0开始
* @param column 起始位置的列,从0开始
* @param step 第几步
*/
public static void traversalChessboard(int[][] chessboard,int row,int column,int step) {
chessboard[row][column] = step;
visited[row * X + column] = true;
List<Point> points = next(new Point(column,row));
sort(points);
while (!points.isEmpty()) {
Point point = points.remove(0);
if (!visited[point.y * X + point.x]) {
traversalChessboard(chessboard,point.y,point.x,step + 1);
}
}
if (step < X * Y && !finished) {
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
}