程序员必会十大算法之骑士周游问题

Posted 独饮敌敌畏丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序员必会十大算法之骑士周游问题相关的知识,希望对你有一定的参考价值。

骑士周游问题又叫马踏棋盘问题

1.未优化前(没有策略)

public class Main {

    //定义棋盘的行数和列数
    static int X = 8;
    static int Y = 8;
    //定义棋盘上的某个点是否被访问过
    static boolean[] isVisited;
    //记录是否周游结束
    static boolean isFinished = false;

    public static void main(String[] args) {
        isVisited = new boolean[X * Y];
        int[][] chessBoard = new int[X][Y];
        //从第一行第一列开始走,第一次走算第一步,即step=1
        travelChessboard(chessBoard,0,0,1);

        //展示下chessBoard
        for (int[] row: chessBoard){
            for (int step: row){
                System.out.print(step + "     ");
            }
            System.out.println();
        }
    }

    /**
     *
     * @param chessBoard 是棋盘,因为递归,所以在不断变化
     * @param row 是马所在的行,也就是y值
     * @param column 是马所在的列,也就是x值
     * @param step 马走到的第几步
     */
    public static void travelChessboard(int[][] chessBoard,int row,int column,int step){
        //假定这一点是可以走的,所以设置已访问,步数也得加上
        chessBoard[row][column] = step;//假定可以走,所以先走过去看看,设置走过去的步数
        isVisited[row * X + column] = true;//假定可以走,所以先走过去看看,设置成已访问

        //得到下一步可以走的点的集合
        ArrayList<Point> nextPoints = getNext(new Point(column, row));
        while (!nextPoints.isEmpty()){
            //首先取出一个来
            Point nextPoint = nextPoints.remove(0);
            //如果这个点没有被访问过
            if (!isVisited[nextPoint.y * X + nextPoint.x]){
                travelChessboard(chessBoard,nextPoint.y,nextPoint.x,step + 1);//这里我一开始写了step++  其实应该是step+1
            }
        }

        //如果假定失败,其实这个点是不可以走的,那么我们就进行回溯!!!
        if (step < X * Y && !isFinished){
            chessBoard[row][column] = 0;
            isVisited[row * X + column] = false;
        }else {
            isFinished = true;
        }
    }
    /**
     * 传入当前点,得到能走的下一个点的集合
     * @param curPoint
     * @return
     */
    public static ArrayList<Point> getNext(Point curPoint){
        //创建结果集
        ArrayList<Point> nextPoints = new ArrayList<>();
        Point nextPoint = new Point();

        //可以走0
        if ((nextPoint.x = curPoint.x + 2) < X && (nextPoint.y = curPoint.y - 1) >= 0){
            nextPoints.add(new Point(nextPoint));
        }
        //表示马可以走1
        if ((nextPoint.x = curPoint.x + 2) < X && (nextPoint.y = curPoint.y + 1) < Y){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走2
        if ((nextPoint.x = curPoint.x + 1) < X && (nextPoint.y = curPoint.y + 2) < Y){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走3
        if ((nextPoint.x = curPoint.x - 1) >= 0 && (nextPoint.y = curPoint.y + 2) < Y){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走4
        if ((nextPoint.x = curPoint.x - 2) >= 0 && (nextPoint.y = curPoint.y + 1) < Y){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走5
        if ((nextPoint.x = curPoint.x - 2) >= 0 && (nextPoint.y = curPoint.y - 1) >= 0){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走6
        if ((nextPoint.x = curPoint.x - 1) >= 0 && (nextPoint.y = curPoint.y - 2) >= 0){
            nextPoints.add(new Point(nextPoint));
        }
        //可以走7
        if ((nextPoint.x = curPoint.x + 1) < X && (nextPoint.y = curPoint.y - 2) >= 0){
            nextPoints.add(new Point(nextPoint));
        }

        return nextPoints;
    }
}

结果略去,等结果时间太长了

2.贪心算法优化后

主要是添加了这个方法
添加了这个方法后,可以减少回溯的次数,极大的提高效率

public static void getNextNext(ArrayList<Point> arrayList){
      //重写集合的sort方法,将其按下一步可选点数目由小到大的顺序排列,再准确一点就是非递减排序(因为有相同点)
      arrayList.sort(new Comparator<Point>() {
          @Override
          public int compare(Point o1, Point o2) {
              //得到o1的下一步可选点的数目
              int count1 = getNext(o1).size();
              //得到o2的下一步可选点的数目
              int count2 = getNext(o2).size();
              if (count1 > count2){
                  return -1;
              }else if (count1 == count2){
                  return 0;
              }else {
                  return 1;
              }
          }
      });
  }

结果

1     16     43     32     3     18     45     22     
42     31     2     17     44     21     4     19     
15     56     53     60     33     64     23     46     
30     41     58     63     54     61     20     5     
57     14     55     52     59     34     47     24     
40     29     38     35     62     51     6     9     
13     36     27     50     11     8     25     48     
28     39     12     37     26     49     10     7  

以上是关于程序员必会十大算法之骑士周游问题的主要内容,如果未能解决你的问题,请参考以下文章

程序员必会十大算法之Prim算法

程序员必会十大算法之贪心算法

程序员必会十大算法之弗洛伊德算法

马踏棋盘(骑士周游问题)

第28章 算法优化体验课 - 骑士周游问题

小甲鱼数据结构和算法--马踏棋盘(骑士周游问题)