马踏棋盘算法(骑士周游问题)
定义:将马随机放在国际象棋的8×8棋盘Board[0~7][0~7]的某个方格中,马按走棋规则进行移动。要求每个方格只进入一次,走遍棋盘上全部64个方格。
核心方法
计算出当前坐标的下一个能走的位置的集合
/**
* @param p
* @return
*/
public List<Point> next(Point p) {
List<Point> nexts = new ArrayList<>();
if (p.x - 2 >= 0 && p.y - 1 >= 0) {
nexts.add(new Point(p.x - 2, p.y - 1));
} // 左上
if (p.x - 1 >= 0 && p.y - 2 >= 0) {
nexts.add(new Point(p.x - 1, p.y - 2));
} // 左上
if (p.x - 2 >= 0 && p.y + 1 < this.Y) {
nexts.add(new Point(p.x - 2, p.y + 1));
}// 左下
if (p.x - 1 >= 0 && p.y + 2 < this.Y) {
nexts.add(new Point(p.x - 1, p.y + 2));
} // 左下
if (p.x + 1 < this.X && p.y + 2 < this.Y) {
nexts.add(new Point(p.x + 1, p.y + 2));
} // 右上
if (p.x + 2 < this.X && p.y + 1 < this.Y) {
nexts.add(new Point(p.x + 2, p.y + 1));
} // 右上
if (p.x + 2 < this.X && p.y - 1 >= 0) {
nexts.add(new Point(p.x + 2, p.y - 1));
} // 右下
if (p.x + 1 < this.X && p.y - 2 >= 0) {
nexts.add(new Point(p.x + 1, p.y - 2));
} // 右下
return nexts;
}
优化思路
使用贪心思想,为了减少回溯的次数,在摆放马的下一次位置的时候,应该选择下下一次能摆放位置较少的位置。
List<Point> points = next(new Point(x, y));
// 使用贪心思想 每次都先选择下一步 可走步数少的先处理 可以有效减少回溯
points.sort(new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
return next(o1).size()-next(o2).size();
}
});
完成代码演示
package com.corn.algorithm.horse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* @author : Jim Wu
* @version 1.0
* @function :
* @since : 2020/8/12 15:09
*/
public class HorseGameDemo {
public static void main(String[] args) {
HorseGame horseGame = new HorseGame(8, 8);
horseGame.play(0, 0, 1);
for (int[] ints : horseGame.chess) {
System.out.println(Arrays.toString(ints));
}
}
}
class HorseGame {
int X;
int Y;
int[][] chess;
boolean[][] visited;
boolean finish;
public HorseGame(int x, int y) {
this.X = x;
this.Y = y;
this.chess = new int[x][y];
this.visited = new boolean[x][y];
}
/**
* 马其实位置
*
* @param x
* @param y
*/
public void play(int x, int y, int step) {
// 标记步数
chess[x][y] = step;
// 设置该顶点已经访问
visited[x][y] = true;
List<Point> points = next(new Point(x, y));
// 使用贪心思想 每次都先选择下一步 可走步数少的先处理 可以有效减少回溯
points.sort(new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
return next(o1).size()-next(o2).size();
}
});
while (points.size() > 0) {
// 下一个可走的顶点
Point nextPoint = points.remove(0);
// 如果当前位置还未走过
if (!this.visited[nextPoint.x][nextPoint.y]) {
// 继续走
this.play(nextPoint.x, nextPoint.y, step + 1);
}
}
// 回溯
if (step < X * Y && !finish) {
this.chess[x][y] = 0;
this.visited[x][y] = false;
} else {
finish = true;
}
}
/**
* @param p
* @return
*/
public List<Point> next(Point p) {
List<Point> nexts = new ArrayList<>();
if (p.x - 2 >= 0 && p.y - 1 >= 0) {
nexts.add(new Point(p.x - 2, p.y - 1));
} // 左上
if (p.x - 1 >= 0 && p.y - 2 >= 0) {
nexts.add(new Point(p.x - 1, p.y - 2));
} // 左上
if (p.x - 2 >= 0 && p.y + 1 < this.Y) {
nexts.add(new Point(p.x - 2, p.y + 1));
}// 左下
if (p.x - 1 >= 0 && p.y + 2 < this.Y) {
nexts.add(new Point(p.x - 1, p.y + 2));
} // 左下
if (p.x + 1 < this.X && p.y + 2 < this.Y) {
nexts.add(new Point(p.x + 1, p.y + 2));
} // 右上
if (p.x + 2 < this.X && p.y + 1 < this.Y) {
nexts.add(new Point(p.x + 2, p.y + 1));
} // 右上
if (p.x + 2 < this.X && p.y - 1 >= 0) {
nexts.add(new Point(p.x + 2, p.y - 1));
} // 右下
if (p.x + 1 < this.X && p.y - 2 >= 0) {
nexts.add(new Point(p.x + 1, p.y - 2));
} // 右下
return nexts;
}
}
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}