马踏棋盘算法
介绍
1.马踏棋盘算法,也称骑士周游问题
2.规则:将马随机放在国际象棋的 8×8 棋盘[0~7][0~7]的某个方格中,马按走棋规则(马走日字)进行移动,要求每个方格只进入一次,走遍棋盘上全部 64 个方格
3.基本思想:图的深度优先搜索 + 贪心算法(优化)
步骤
1.创建一个二维数组代表棋盘
2.将当前位置设置为已经访问,把当前马在棋盘的位置标记为第几步(step),然后根据当前位置,计算马还能走哪些位置,并放入ArrayList,最多有8个位置
3.获取到ArrayList后,用贪心算法优化
4.遍历ArrayList中存放的所有位置,判断哪个位置可以走通,如果走通,就继续,走不通,就回溯
5.判断是否走完整个棋盘,使用step和应该走的步数比较,如果没有达到数量,则表示没有完成任务,并将整个棋盘置0
贪心算法优化ArrayList
1.基本思想:根据当前这个一步的所有的下一步的选择位置,进行非递减(即不严格递增)排序, 减少回溯的次数
步骤
(1)传入Comparotor,重写ArrayList的sort方法
(2)获取ArrayList所有位置的通路个数,按非递减排序
(3)即当前位置的下一步的下一步通路最少,就优先选择
代码实现
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class KnightTravel {//骑士周游问题
public int row;//棋盘的行数
public int column;//棋盘的列数
public int[][] chessboard;//棋盘
public boolean[][] visited;//标记棋盘的各个位置是否被访问过,true:已访问
public boolean finished;//标记是否棋盘的所有位置都被访问,若为true,表示算法计算成功
public int step = 1;//初始为第一步
public static void main(String[] args) {
KnightTravel knight = new KnightTravel(8, 8);
long start = System.currentTimeMillis();
knight.travel(knight.chessboard, 0, 0, knight.step);
long end = System.currentTimeMillis();
System.out.println("共耗时: " + (end - start) + " 毫秒");
knight.result();
}
public KnightTravel(int row, int column) {
this.row = row;
this.column = column;
this.chessboard = new int[row][column];
this.visited = new boolean[row][column];
}
public void result() {//打印算法结果
for (int[] row : chessboard) {
System.out.println(Arrays.toString(row));
}
}
//马踏棋盘算法
//chessboard:棋盘,row:马儿当前的位置的行,从0开始,column:马儿当前的位置的列 ,从0开始,step:第几步,初始位置是第1步
public void travel(int[][] chessboard, int row, int column, int step) {
chessboard[row][column] = step;
visited[row][column] = true; //标记该位置已经访问
//获取当前位置可以走的下一个位置的集合
ArrayList<Point> access = next(new Point(column, row));
sort(access);//对access进行非递减排序
while (!access.isEmpty()) {
Point next = access.remove(0);//取出下一个可以走的位置
if (!visited[next.y][next.x]) {//判断该点是否已经访问过
travel(chessboard, next.y, next.x, step + 1);
}
}
if (step < this.row * this.column && !finished) {
//无路可走且未走完,就回溯到上一位置
chessboard[row][column] = 0;
visited[row][column] = false;
} else {
//成功走完时,finished是防止回溯时将最优解覆盖掉
finished = true;
}
}
//根据当前位置(curPoint),计算马还能走哪些位置(point),并放入一个集合中(ArrayList), 最多有8个位置
public ArrayList<Point> next(Point curPoint) {
//储存马在当前位置的通路
ArrayList<Point> access = new ArrayList<>();
//Point对象中,属性x代表列,属性y代表行
Point point = new Point();
//以下操作,判断马的8个方向是否可行,并记录通路位置,但不记录该位置是否已访问
if ((point.x = curPoint.x - 2) >= 0 && (point.y = curPoint.y - 1) >= 0) {
access.add(new Point(point));
}
if ((point.x = curPoint.x - 1) >= 0 && (point.y = curPoint.y - 2) >= 0) {
access.add(new Point(point));
}
if ((point.x = curPoint.x + 1) < column && (point.y = curPoint.y - 2) >= 0) {
access.add(new Point(point));
}
if ((point.x = curPoint.x + 2) < column && (point.y = curPoint.y - 1) >= 0) {
access.add(new Point(point));
}
if ((point.x = curPoint.x + 2) < column && (point.y = curPoint.y + 1) < row) {
access.add(new Point(point));
}
if ((point.x = curPoint.x + 1) < column && (point.y = curPoint.y + 2) < row) {
access.add(new Point(point));
}
if ((point.x = curPoint.x - 1) >= 0 && (point.y = curPoint.y + 2) < row) {
access.add(new Point(point));
}
if ((point.x = curPoint.x - 2) >= 0 && (point.y = curPoint.y + 1) < row) {
access.add(new Point(point));
}
return access;
}
//根据当前这个一步的所有的下一步的选择位置,进行非递减(不严格递增)排序, 减少回溯的次数
public void sort(ArrayList<Point> access) {
access.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;
}
}
});
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战