需求来源:4399之马踏棋盘小游戏:http://www.4399.com/flash/146267_2.htm
游戏规则:将国际象棋马放入一个6x6的棋盘中,随机指定一个初始位置,求棋子走完棋盘的步法
解题思路:二维数组模拟棋盘,记录其步数,再使用一个boolean型的二维数组模拟棋盘,判断其位置是否已经走过
使用Java的Point类表示棋子,根据国际象棋马儿的走法可知一个棋子最多有8种走法编写一个方法,返回值
为当前棋子所有下一位置的集合,然后递归调用该方法,每次调用步数step 1,递归回溯为判断步数是否已经
到达棋盘的位置个数length,如果递归深度即步数step未到达length则回溯(将棋盘步数和已访问位置重置)
优化:递归先走下一棋子步数最多的位置,这样可以有效减少代码回溯的次数(贪心算法)
算法思想:动态规划算法之回溯法
优化思想:贪心算法减少回溯次数
代码实现:(回溯法)
代码语言:javascript复制import java.awt.Point;
import java.util.LinkedList;
/**
* 马踏棋盘算法
* 回溯法、贪心算法
* @author com
*
*/
public class ChessBoard {
private int X; // 棋盘的横坐标
private int Y; // 棋盘的纵坐标
private int[][] checkerboard; // 自定义二维数组棋盘
private boolean[][] visited; // 判断棋子是否访问过
private boolean finished; // 判断递归是否完成
private Point p; // 递归取出的棋子位置
// 构造函数初始化对象
public ChessBoard(int x,int y) {
X = x; Y = y;
checkerboard = new int[x][y];
visited = new boolean[x][y];
}
public static void main(String[] args) {
System.out.println("----------------- 游戏开始 -----------------n");
long start = System.currentTimeMillis();
ChessBoard chess = new ChessBoard(6,6); // 初始化棋盘
chess.traceback(1, 3, 1); // 递归 回溯,完成棋盘走法
// 打印棋盘结果
for(int[] x:chess.checkerboard) {
for(int y:x) {
System.out.printf("%dt",y);
}System.out.println("n");
}
long end = System.currentTimeMillis();
long time = (end - start)/1000;
System.out.println("一共耗时: " time " 秒");
}
/**
* 核心算法,回溯实现
* @param checkerboard 棋盘
* @param visited 是否访问标记
* @param row 棋子当前行坐标
* @param col 棋子当前列坐标
* @param step 棋子当前步数
*/
public void traceback(int x,int y,int step) {
checkerboard[x][y] = step; // 将当前的步数记录在棋盘上
visited[x][y] = true; // 将当前位置标记为已访问过
LinkedList list = next(new Point(x,y)); // 当前点所有可能步数的集合
// 循环遍历集合,直到为空跳出循环
while(!list.isEmpty()) {
p = list.remove(0); // 取出下一个可以走的位置
// 判断该点是否已经访问过
if(!visited[p.x][p.y]) {
traceback(p.x, p.y, step 1); // 递归
}
}
// 回溯
if(step < X*Y && !finished) {
checkerboard[x][y] = 0; // 棋盘步数重置
visited[x][y] = false; // 访问记录重置
}else {
finished = true;
}
}
/**
* 将当前棋子的下一个位置的所有位置存入list中
* @param curPoint 当前棋子
* @return list 棋子下一个位置所有可能的集合
*/
public LinkedList next(Point curPoint){
LinkedList list = new LinkedList();
Point p = new Point();
// 棋子可以走位置1,x 2=0
if((p.x = curPoint.x 2) < X && (p.y = curPoint.y - 1) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置2,x 1=0
if((p.x = curPoint.x 1) < X && (p.y = curPoint.y - 2) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置3,x-1>=0,y-2>=0
if((p.x = curPoint.x - 1) >= 0 && (p.y = curPoint.y - 2) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置4,x-2>=0,y-1>=0
if((p.x = curPoint.x - 2) >= 0 && (p.y = curPoint.y - 1) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置5,x-2>=0,y 1= 0 && (p.y = curPoint.y 1) < Y) {
list.add(new Point(p));
}
// 棋子可以走位置6,x-1>0,y 2= 0 && (p.y = curPoint.y 2) < Y) {
list.add(new Point(p));
}
// 棋子可以走位置7,x 1
算法优化:(贪心算法)
import java.awt.Point;
import java.util.Comparator;
import java.util.LinkedList;
/**
* 马踏棋盘算法
* 回溯法、贪心算法
* @author com
*
*/
public class ChessBoard {
private int X; // 棋盘的横坐标
private int Y; // 棋盘的纵坐标
private int[][] checkerboard; // 自定义二维数组棋盘
private boolean[][] visited; // 判断棋子是否访问过
private boolean finished; // 判断递归是否完成
private Point p; // 递归取出的棋子位置
// 构造函数初始化对象
public ChessBoard(int x,int y) {
X = x; Y = y;
checkerboard = new int[x][y];
visited = new boolean[x][y];
}
public static void main(String[] args) {
System.out.println("----------------- 游戏开始 -----------------n");
long start = System.currentTimeMillis();
ChessBoard chess = new ChessBoard(6,6); // 初始化棋盘
chess.traceback(1, 3, 1); // 递归 回溯,完成棋盘走法
// 打印棋盘结果
for(int[] x:chess.checkerboard) {
for(int y:x) {
System.out.printf("%dt",y);
}System.out.println("n");
}
long end = System.currentTimeMillis();
long time = (end - start)/1000;
System.out.println("一共耗时: " time " 秒");
}
/**
* 核心算法,回溯实现
* @param checkerboard 棋盘
* @param visited 是否访问标记
* @param row 棋子当前行坐标
* @param col 棋子当前列坐标
* @param step 棋子当前步数
*/
public void traceback(int x,int y,int step) {
checkerboard[x][y] = step; // 将当前的步数记录在棋盘上
visited[x][y] = true; // 将当前位置标记为已访问过
LinkedList list = next(new Point(x,y)); // 当前点所有可能步数的集合
sort(list); // 贪心算法升序排序优化
// 循环遍历集合,直到为空跳出循环
while(!list.isEmpty()) {
p = list.remove(0); // 取出下一个可以走的位置
// 判断该点是否已经访问过
if(!visited[p.x][p.y]) {
traceback(p.x, p.y, step 1); // 递归
}
}
// 回溯
if(step < X*Y && !finished) {
checkerboard[x][y] = 0; // 棋盘步数重置
visited[x][y] = false; // 访问记录重置
}else {
finished = true;
}
}
/**
* 将当前棋子的下一个位置的所有位置存入list中
* @param curPoint 当前棋子
* @return list 棋子下一个位置所有可能的集合
*/
public LinkedList next(Point curPoint){
LinkedList list = new LinkedList();
Point p = new Point();
// 棋子可以走位置1,x 2=0
if((p.x = curPoint.x 2) < X && (p.y = curPoint.y - 1) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置2,x 1=0
if((p.x = curPoint.x 1) < X && (p.y = curPoint.y - 2) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置3,x-1>=0,y-2>=0
if((p.x = curPoint.x - 1) >= 0 && (p.y = curPoint.y - 2) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置4,x-2>=0,y-1>=0
if((p.x = curPoint.x - 2) >= 0 && (p.y = curPoint.y - 1) >= 0) {
list.add(new Point(p));
}
// 棋子可以走位置5,x-2>=0,y 1= 0 && (p.y = curPoint.y 1) < Y) {
list.add(new Point(p));
}
// 棋子可以走位置6,x-1>0,y 2= 0 && (p.y = curPoint.y 2) < Y) {
list.add(new Point(p));
}
// 棋子可以走位置7,x 1 list) {
list.sort(new Comparator() {
@Override
public int compare(Point p1, Point p2) {
return next(p1).size() - next(p2).size();
}
});
}
}
运行结果:
棋子最多有8个位置可以走(位置对应代码注释的位置x)
游戏链接:
http://www.4399.com/flash/146267_2.htm
游戏成功截图: