java学习笔记之马踏棋盘算法

马踏棋盘或骑士周游问题

1、马踏棋盘算法也被称为骑士周游问题
2、将马随机放在国际象棋的 8×8 棋盘 Board[0~7][0~7]的某个方格中,马按走棋规则(马走日字)进行移动。要求每个方格只进入一次,走遍棋盘上全部 64 个方格

思路

会使用到深度优先思想和类似迷宫问题的寻路策略问题,和八皇后问题也有相似。

1、用一个二维数组建立整张棋盘。用另外一个二维数组保存棋盘的每一个位置是否走过
2、马在棋盘上有一个初始位置,将这个位置设为已走过,并将步数设为1.
3、获得在这个位置上,马下一步能走的位置集合。
4、遍历集合里的所有位置,如果那个位置没走过,下一步(步数+1)就走它(递归)
5、设置递归结束的标志.用一个布尔变量标志游戏是否成功。当游戏成功时,步数应该等于棋盘格子数。假如某一次,马走完了所有能走的下一步位置,步数还小于棋盘格子数并且还没成功,说明这个位置不能成功的完成游戏,就把这个位置恢复原样(棋盘设为0,设为未走过),接下来的递归会重新去寻找合适的路。如果步数等于棋盘总格子数,说明游戏成功,把标志的布尔变量设为true,这样在层层返回时就不会再进入上面的条件,递归就会逐渐结束而不会深入下去。

涉及到的方法:

根据此时的位置,判断马接下来能走的位置集合。
x的值代表列而y的值代表行
马是按照日字走的,所有当它在中间时最多有8种位置可以走,一 一判断那个位置是否超过棋盘边界。
每种可能都是if,而不是if-else if,因为要获得所有的可能性,而不是找出一个
假如list时一定要新建一个坐标,不能使用同一个,不然值就会互相影响

/**
     * 根据现在的坐标返回可以走的坐标 x列y行
     *
     * @param current
     * @return
     */
    public static ArrayList<Point> findWay(Point current) {
        ArrayList<Point> res = new ArrayList<>();
        //可以走的坐标
        Point p = new Point();
        //5
        if ((p.x = current.x - 2) >= 0 && (p.y = current.y - 1) >= 0) {
            res.add(new Point(p));
        }
        //6
        if ((p.x = current.x - 1) >= 0 && (p.y = current.y - 2) >= 0) {
            res.add(new Point(p));
        }
        //7
        if ((p.x = current.x + 1) < X && (p.y = current.y - 2) >= 0) {
            res.add(new Point(p));
        }
        //0
        if ((p.x = current.x + 2) < X && (p.y = current.y - 1) >= 0) {
            res.add(new Point(p));
        }
        //1
        if ((p.x = current.x + 2) < X && (p.y = current.y + 1) < Y) {
            res.add(new Point(p));
        }
        //2
        if ((p.x = current.x + 1) < X && (p.y = current.y + 2) < Y) {
            res.add(new Point(p));
        }
        //3
        if ((p.x = current.x - 1) >= 0 && (p.y = current.y + 2) < Y) {
            res.add(new Point(p));
        }
        //4
        if ((p.x = current.x - 2) >= 0 && (p.y = current.y + 1) < Y) {
            res.add(new Point(p));
        }
        return res;
    }

马塔棋盘

不能单纯以step < X * Y来判断是否完成游戏,因为递归回溯时步数也会回溯,所以要设置一个变量

 /**
     * 马踏棋盘算法
     *
     * @param chess 棋盘
     * @param row   坐标行
     * @param col   坐标列
     * @param step  步数
     */
    public static void traversalChessboard(int[][] chess, int row, int col, int step) {
        //先走一步
        chess[row][col] = step;
        visit[row][col] = true;
        //下一步能走的地
        ArrayList<Point> way = findWay(new Point(col, row));
        while (!way.isEmpty()) {
            //取出一个能走的地方
            Point point = way.remove(0);
            //走下一步
            if (!visit[point.y][point.x]) {
                traversalChessboard(chess, point.y, point.x, step + 1);
            }

        }
        //判断是否完成游戏,如果没完成就要回溯
        if (step < X * Y && !finshed) {
            chess[row][col] = 0;
            visit[row][col] = false;
        }else {
            finshed=true;
        }
    }

优化

这样计算效率比较低,算法比较慢。实际上当我们获得下一步可以走的位置数组时是按照固定的56701234顺序排列的,但是这样效率不高,我们在考虑到走下一步时,应该先走对应下一步的可能性最少的那一步,比如如果7的下一步有3种可能,而5的下一步有6种可能,那先7后5的效率会更高。

所以我们可以使用贪心算法对获得的这个步数集合根据他们下一步的可能性进行由小到大的排序。

/**
     * 贪心算法优化
     * @param ps
     */
    public static void sort(ArrayList<Point> ps){
        ps.sort(new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                int way1 = findWay(o1).size();
                int way2 = findWay(o2).size();
                if(way1<way2){
                    return -1;
                }else if(way1==way2){
                    return 0;
                }else {
                    return 1;
                }
            }
        });
}

对Comparetor.compare(o1, o2)方法的返回值,如果返回的值小于零,则不交换两个o1和o2的位置;如果返回的值大于零,则交换o1和o2的位置。 注意,不论在compare(o1, o2)中是如何实现的(第一种实现方式是 o1-02, 第二种实现方式是 o2 - o1),都遵循上述原则,即返回值小于零,则交换o1和o2的位置;返回值大于零,则不交换o1和o2的位置。 所以,如果采用第一种实现方式,即 o1 - o2, 那么将是升序排序。因为在原始排序中o1在o2的前边,如果o1小于o2,那么o1 - o2小于零,即返回值是小于零,但是小于零是不会交换o1和o2的位置的,所以o1依然排在o2的前边,是升序;如果o1大于o2,那么o1 - o2大于零,即返回值是大于零,大于零是要交换o1和o2的位置的,所以要改变原始排序中o1和o2的位置,那么依然是升序

最终代码

package algorithm;

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

/**
 * 马踏棋盘算法
 */
public class HorseChessboard {
    static int X;//列
    static int Y;//行
    static boolean[][] visit;
    static boolean finshed;

    public static void main(String[] args) {
        X = 8;
        Y = 8;
        visit = new boolean[X][Y];
        finshed = false;
        int[][] chess = new int[X][Y];
        long s = System.currentTimeMillis();

        traversalChessboard(chess, 2, 0, 1);
        long e=System.currentTimeMillis();
        System.out.println(e-s);

        for (int i = 0; i < chess.length; i++) {
            System.out.println(Arrays.toString(chess[i]));
        }

    }

    /**
     * 马踏棋盘算法
     *
     * @param chess 棋盘
     * @param row   坐标行
     * @param col   坐标列
     * @param step  步数
     */
    public static void traversalChessboard(int[][] chess, int row, int col, int step) {
        //先走一步
        chess[row][col] = step;
        visit[row][col] = true;
        //下一步能走的地
        ArrayList<Point> way = findWay(new Point(col, row));
        sort(way);
        while (!way.isEmpty()) {
            //取出一个能走的地方
            Point point = way.remove(0);
            //走下一步
            if (!visit[point.y][point.x]) {
                traversalChessboard(chess, point.y, point.x, step + 1);
            }

        }
        if (step < X * Y && !finshed) {
            chess[row][col] = 0;
            visit[row][col] = false;
        }else {
            finshed=true;
        }
    }

    /**
     * 根据现在的坐标返回可以走的坐标 x列y行
     *
     * @param current
     * @return
     */
    public static ArrayList<Point> findWay(Point current) {
        ArrayList<Point> res = new ArrayList<>();
        //可以走的坐标
        Point p = new Point();
        //5
        if ((p.x = current.x - 2) >= 0 && (p.y = current.y - 1) >= 0) {
            res.add(new Point(p));
        }
        //6
        if ((p.x = current.x - 1) >= 0 && (p.y = current.y - 2) >= 0) {
            res.add(new Point(p));
        }
        //7
        if ((p.x = current.x + 1) < X && (p.y = current.y - 2) >= 0) {
            res.add(new Point(p));
        }
        //0
        if ((p.x = current.x + 2) < X && (p.y = current.y - 1) >= 0) {
            res.add(new Point(p));
        }
        //1
        if ((p.x = current.x + 2) < X && (p.y = current.y + 1) < Y) {
            res.add(new Point(p));
        }
        //2
        if ((p.x = current.x + 1) < X && (p.y = current.y + 2) < Y) {
            res.add(new Point(p));
        }
        //3
        if ((p.x = current.x - 1) >= 0 && (p.y = current.y + 2) < Y) {
            res.add(new Point(p));
        }
        //4
        if ((p.x = current.x - 2) >= 0 && (p.y = current.y + 1) < Y) {
            res.add(new Point(p));
        }
        return res;
    }

    /**
     * 贪心算法优化
     * @param ps
     */
    public static void sort(ArrayList<Point> ps){
        ps.sort(new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                int way1 = findWay(o1).size();
                int way2 = findWay(o2).size();
                if(way1<way2){
                    return -1;
                }else if(way1==way2){
                    return 0;
                }else {
                    return 1;
                }
            }
        });
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java数据结构和算法之马踏棋盘算法

    本文实例为大家分享了java实现算法之马踏棋盘的具体代码,供大家参考,具体内容如下 一.马踏棋盘算法介绍 马踏棋盘算法也被称为骑士周游问题将马随机放在国际象棋的8×8棋盘Board[0-7][0-7]的某个方格中,马按走棋规则(马走日字)进行移动.要求每个方格只进入一次,走遍棋盘上全部64个方格 二.骑士周游问题的思路分析 1.创建棋盘 chessBoard , 是一个二维数组2.将当前位置设置为已经访问,然后根据当前位置,计算马儿还能走哪些位置,并放入到一个集合中(ArrayList), 最多

  • java使用swing绘制国际象棋棋盘

    本文实例为大家分享了java使用swing绘制国际象棋棋盘的具体代码,供大家参考,具体内容如下 1.完整代码 import java.awt.Color; import java.awt.Point; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JLabel; public class guo_ji_xiang_qi_qipan { public static void main(

  • java实现马踏棋盘游戏

    用java实现马踏棋盘游戏算法,供大家参考,具体内容如下 在4399小游戏中有这样一个游戏 这是代码实现 package com.HorseChess; import java.awt.*; import java.util.ArrayList; import java.util.Comparator; import java.util.Scanner; public class HorseChess {     private static int X;     private static

  • java绘制五子棋棋盘

    本文实例为大家分享了java绘制五子棋棋盘的具体代码,供大家参考,具体内容如下 源码: import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class Demo extends JFrame { //背景图片 Buffere

  • Java实现马踏棋盘算法

    本文实例为大家分享了Java实现马踏棋盘的具体代码,供大家参考,具体内容如下 马在某个点最多可能有8种走法,用递归和回溯实现. 注:代码中,查找下一个可走坐标是从右下第一个开始的,也就是图中的4.可以通过修改a,b...h的值来改变顺序. 代码: /**  * 马踏棋盘算法   * 递归和回溯  *  */ public class HorseStep {          public static int X = 8;     public static int Y = 8;        

  • java绘制国际象棋与中国象棋棋盘

    JAVA API 中的绘制图形类的paint()方法,我们可以轻松绘制中国象棋与国际象棋的棋盘.详见代码:  一.中国象棋棋盘代码 import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class ChineseChese extends Frame{

  • Java实现简单棋盘存档和读取功能

    最近实现研究了下五子棋的存档,主要实现是将残局的五子棋棋盘保存到本地文件中,需要读取棋局时能够从本地文件获取,并展示出原有的残局局面. 主要思路 如上图所示,第一个表格是11*11的棋局,可以转换成11行11列的二维数组,1代表黑子,2代表蓝子,转换成第二个表格所示的二维数组.在保存时,考虑到二维数组中0大部分是没有被占用的空间,所以我将二维数组转换成了一个n行3列的稀疏数组,将所占用的空间压缩,保存到本地文件中.其中稀疏数组的第一行row表示11行,col表示11列,val表示除0以外的有效数

  • java编程实现国际象棋棋盘

    本文实例为大家分享了java编程实现国际象棋棋盘的具体代码,供大家参考,具体内容如下 问题描述: 打印出国际象棋棋盘(黑白交错) 问题分析: 棋盘由八块黑白相间的方块组成,通过swing编程实现.其中用标签来实现方块,在方块中填充黑或白色.通过i,j来遍历行和列,以i和j的值来判断填充什么颜色 代码分析 import javax.swing.*; import java.awt.*; public class _2ChessBoard { public static void main(Stri

  • java实现马踏棋盘的算法

    本文实例为大家分享了java实现马踏棋盘的具体代码,供大家参考,具体内容如下 马踏棋盘算法介绍 8X8棋盘,马走日字,要求每个方格只进入一次,走遍棋盘上全部64个方格. 代码: public class HorseChessBoard {     private static int X;//棋盘的列数     private static int Y;//棋盘的行数     //创建一个数组,标记棋盘的各个位置是否被访问过     private static boolean visited[

  • java实现马踏棋盘的完整版

    本文实例为大家分享了java实现马踏棋盘的具体代码,供大家参考,具体内容如下 马踏棋盘很好实现,但有时运行起来特别慢,还可能出不来结果,在这里要用到贪心算法来优化,即找出最难走的路径,也就是下下步可下棋的位置最少. 下面给出该算法完整代码: /*      * 马踏棋盘问题:(贪婪法求解)      * 棋盘有64个位置,"日"字走法,刚好走满整个棋盘      */     //下一个走法的方向类     class Direction{         int x;        

随机推荐