整个问题的解决思路就是递归回溯+贪心算法
递归代码如下:
/**
* 完成骑士周游问题的算法
* @param chessboard 棋盘
* @param row 骑士当前所在位置的行(从0开始)
* @param column 骑士当前所在位置的列(从0开始)
* @param step 第几步(从1开始)
*/
public static void traversalChessboard(int[][] chessboard, int row, int column, int step){
chessboard[row][column] = step;
visited[ row*X + column ] = true;//标记该位置已经访问
ArrayList<Point> ps = next(new Point(column, row));
//对ps进行非递减排序来减少递归次数
sort(ps);
//遍历ps
while (!ps.isEmpty()){
Point p = ps.remove(0);
if (!visited[p.y * X + p.x]){
traversalChessboard( chessboard, p.y, p.x, step + 1 );//递归
}
}
if (step < X * Y && !finished ){
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
学完这个感觉到贪心算法是真的牛逼,废话少说,直接上图!
没使用贪心算法时耗费46478毫秒:
使用了贪心算法后只用了39毫秒:
贪心算法的思路是对马下一步能走的位置的集合进行非递减排序,通过减少回溯的次数来达到缩短搜索时间的目的。代码如下:
/**
* 对马下一步能走的位置的集合进行非递减排序,通过减少回溯的次数来达到缩短搜索时间的目的
* @param ps 马下一步能走的位置的集合
*/
public static void sort(ArrayList<Point> ps){
ps.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;
}
}
});
}
完整代码如下:
package Algorithm.horse;
import java.awt.*;
import java.util.ArrayList;
import java.util.Comparator;
/**
* 马踏棋盘
*/
public class HorseChessboard {
private static int X;//列
private static int Y;//行
private static boolean[] visited;//该数组标记各个位置是否被访问过
private static boolean finished;//true表示成功,false表示失败
public static void main(String[] args) {
X = Y = 8;
int row = 1;
int column = 1;
int[][] chessboard = new int[X][Y];//创建棋盘
visited = new boolean[X * Y];
System.out.println("马踏棋盘开始:");
long start = System.currentTimeMillis();
traversalChessboard(chessboard, row - 1, column - 1, 1);
long end = System.currentTimeMillis();
System.out.println("共耗时:"+ (end - start) +"毫秒");
//输出结果
for ( int[] rows: chessboard ) {
for ( int step: rows ) {
System.out.print(step+"\t");
}
System.out.println();
}
}
/**
* 完成骑士周游问题的算法
* @param chessboard 棋盘
* @param row 骑士当前所在位置的行(从0开始)
* @param column 骑士当前所在位置的列(从0开始)
* @param step 第几步(从1开始)
*/
public static void traversalChessboard(int[][] chessboard, int row, int column, int step){
chessboard[row][column] = step;
visited[ row*X + column ] = true;//标记该位置已经访问
ArrayList<Point> ps = next(new Point(column, row));
//对ps进行非递减排序来减少递归次数
sort(ps);
//遍历ps
while (!ps.isEmpty()){
Point p = ps.remove(0);
if (!visited[p.y * X + p.x]){
traversalChessboard( chessboard, p.y, p.x, step + 1 );//递归
}
}
if (step < X * Y && !finished ){
chessboard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
/**
* 根据当前位置计算马还能走哪些位置,并将这些位置放入到一个集合中
* @param curPoint
* @return
*/
public static ArrayList<Point> next(Point curPoint){
ArrayList<Point> ps = new ArrayList<Point>();
Point p1 = new Point();
if ( (p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y - 1) >= 0 ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 2) >= 0 ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y - 2) >= 0 ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y - 1) >= 0 ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y + 1) < Y ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y + 2) < Y ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y + 2) < Y ) {
ps.add(new Point(p1));
}
if ( (p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y + 1) < Y ) {
ps.add(new Point(p1));
}
return ps;
}
/**
* 对马下一步能走的位置的集合进行非递减排序,通过减少回溯的次数来达到缩短搜索时间的目的
* @param ps 马下一步能走的位置的集合
*/
public static void sort(ArrayList<Point> ps){
ps.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;
}
}
});
}
}