骑士周游问题
作者:互联网
算法
1. 骑士周游问题
-
马踏棋盘算法也被称为骑士周游问题
-
将马随机放在国际象棋的 8x8 棋盘中
[0~7][0~7]
的某个方格中,马鞍走起规则(马走日字)进行移动。要求每个方格只进入一次,走遍棋盘上全部64个方格
3. 会使用到图的遍历算法(DFS)+ 贪心算法优化
1.1 普通方法
package com.example.mhl_demo.day01;
import java.awt.*;
import java.util.ArrayList;
/**
* 骑士周游
*/
public class HouseChessBoard {
//定义属性
private static int X = 6;//表示 col
private static int Y = 6;//表示 row
//棋盘
private static int[][] chessBoard = new int[Y][X];
//记录某个位置是否走过
private static boolean[] visited = new boolean[X * Y];
//记录马儿是否遍历完棋盘
private static boolean finished = false;
public static void main(String[] args) {
int row = 5;
int col = 5;
//测试
long start = System.currentTimeMillis();
traversalChessBoard(chessBoard,row-1,col - 1,1);
long end = System.currentTimeMillis();
System.out.println("运行时间:" + (end - start) + "ms");
//输出当前棋盘的情况
for (int[] rows : chessBoard) {
for (int step : rows) {
System.out.print(step + "\t");
}
System.out.println();
}
}
/*
编写最核心的算法,遍历棋盘,入股遍历成功,finished 设置为true,
并且将马儿走的每一步 step,记录到 chessBoard
*/
public static void traversalChessBoard(int[][] chessBoard,int row,int col,int step){
//先把step记录到chessBoard
chessBoard[row][col] = step;
//把这个位置,设置为已访问
visited[row * X + col] = true;
//获取当前位置可以走的下一个位置有哪些
ArrayList<Point> ps = next(new Point(col, row));
//遍历
while (!ps.isEmpty()){
//取出当前ps的第一个位置
Point p = ps.remove(0);
//判断该位置是否走过,如果没有没有走过,就递归遍历
if (!visited[p.y * X + p.x]){
//可以走
traversalChessBoard(chessBoard,p.y,p.x,step + 1);
}
}
/*
当退出while,查看是否遍历成功.
如果没有遍历成功,就重置当前位置,回溯
如果成功,设置走完整个棋盘
*/
if (step < X * Y && !finished ){
//重置
chessBoard[row][col] = 0;
visited[row * X + col] = false;
}else {
finished = true;
}
}
//编写方法,可以获取当前位置的下一步的所有位置
public static ArrayList<Point> next(Point curPoint) {
//创建一个ArrayList
ArrayList<Point> ps = new ArrayList<>();
//创建一个point(点),准备放入ps
Point p1 = new Point();
//判断是否可以走5的位置
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 1) >=0){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走6的位置
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y - 2) >=0){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走7的位置
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y - 2) >=0){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走0的位置
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y - 1) >=0){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走1的位置
if ((p1.x = curPoint.x + 2) < X && (p1.y = curPoint.y + 1) < Y){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走2的位置
if ((p1.x = curPoint.x + 1) < X && (p1.y = curPoint.y + 2) < Y){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走3的位置
if ((p1.x = curPoint.x - 1) >= 0 && (p1.y = curPoint.y + 2) < Y){
//这里一定new point
ps.add(new Point(p1));
}
//判断是否可以走4的位置
if ((p1.x = curPoint.x - 2) >= 0 && (p1.y = curPoint.y + 1) < Y){
//这里一定new point
ps.add(new Point(p1));
}
return ps;
}
}
1.2 贪心算法优化
使用贪心算法,进行优化,提高速度
分析
- 我们现在走的位置,是按照我们的顺时针来挑选位置,因此选择的这个点的下一个可以走的位置的个数是不确定。
- 优化思路:我们应该选择下一个点的下一个点可以走的位置较少的点,开始走,这样可以减少回溯的次数
- 代码:对我们的 ps 集合 按照可以走的下一个位置的次数进行排序,升序排序。
/*
编写一个方法,对ps的各个位置,可以走的下一个位置的次数进行排序,
按照从小到大的顺序进行排序
*/
public static void sort(ArrayList<Point> ps){
ps.sort((o1, o2) -> next(o1).size() - next(o2).size());
}
在traversalChessBoard
中获取next
方法之后 进行排序
/*
编写最核心的算法,遍历棋盘,入股遍历成功,finished 设置为true,
并且将马儿走的每一步 step,记录到 chessBoard
*/
public static void traversalChessBoard(int[][] chessBoard,int row,int col,int step){
//先把step记录到chessBoard
chessBoard[row][col] = step;
//把这个位置,设置为已访问
visited[row * X + col] = true;
//获取当前位置可以走的下一个位置有哪些
ArrayList<Point> ps = next(new Point(col, row));
//排序
sort(ps);
//遍历
while (!ps.isEmpty()){
//取出当前ps的第一个位置
Point p = ps.remove(0);
//判断该位置是否走过,如果没有没有走过,就递归遍历
if (!visited[p.y * X + p.x]){
//可以走
traversalChessBoard(chessBoard,p.y,p.x,step + 1);
}
}
}
标签:ps,周游,p1,Point,int,问题,curPoint,new,骑士 来源: https://blog.csdn.net/weixin_42553198/article/details/121455544