算法设计与分析: 2-4 马的Hamilton周游路线问题

2-4 马的Hamilton周游路线问题


问题描述

8*8的国际象棋棋盘上的一只马,恰好走过除起点外的其他63个位置各一次,最后回到起点,这条路线称为马的一条Hamilton周游路线。对于给定的m*n的国际象棋棋盘,m和n均为大于5的偶数,且|m-n|≤2,试设计一个分治算法找出马的一条Hamilton周游路线。


回溯法

Java

public class Main {
   

    private static int max = 101;
    private static int[][] board = new int[max][max];
    private static int startX, startY;
    private static int[] dx = {-2, -1, 1, 2, -2, -1, 2, 1};
    private static int[] dy = {-1, -2, -2, -1, 1, 2, 1, 2};
    private static int m = 8;//行
    private static int n = 6;//列

    public static void main(String[] args) {
        startX = 2;
        startY = 2;

        int number = 1;
        board[startX][startY] = 1;

        backtrack(startX, startY, number);
    }

    private static void backtrack(int x, int y, int num) {
        //已经走完棋盘中所有的点
        if (num == n * m && isNextStepStartPoint(x, y)) {
            print(n, m);
            System.exit(1);
        }

        //表示每一个格都有八种走法
        for (int i = 0; i < 8; i++) {
            int nextX = x + dx[i];
            int nextY = y + dy[i];
            if (isNextStepOk(nextX, nextY)) {
                //走到下一个位置,设置其序号为 number+1
                board[nextX][nextY] = num + 1;
                backtrack(nextX, nextY, num + 1);
                //回溯
                board[nextX][nextY] = 0;
            }
        }

    }

    //判断下一步是否回到起点
    private static boolean isNextStepStartPoint(int x, int y) {
        for (int i = 0; i < 8; i++) {
            if (x + dx[i] == startX && y + dy[i] == startY)
                return true;
        }

        return false;
    }

    private static void print(int n, int m) {
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++)
                System.out.print(String.format("%4d", board[i][j]));

            System.out.println();
        }

        if(board[1][1] != 1){
            System.out.println("-------Change to start from (1,1)--------");
            int tmpStart = board[1][1];
            for(int i=1; i<=m; i++)
                for(int j=1; j<=n; j++)
                    if(board[i][j] > tmpStart)
                        board[i][j] = board[i][j]-tmpStart+1;
                    else if(board[i][j] < tmpStart)
                        board[i][j] = board[i][j]+m*n-tmpStart+1;
                    else
                        board[i][j] = 1;
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++)
                System.out.print(String.format("%4d", board[i][j]));

            System.out.println();
        }
    }

    //参数x,y 表示棋盘的位置
    //检测(x,y) 对应位置在棋盘中是否合法
    private static boolean isNextStepOk(int x, int y) {
        if (x < 1 || y < 1 || x > m || y > n || board[x][y] != 0)
            return false;
        else
            return true;

    }
}

Output

   7   4  19  48  21  44
  18   1   6  45  34  47
   5   8   3  20  43  22
   2  17  10  33  46  35
   9  14  27  36  23  42
  28  11  16  39  32  37
  15  26  13  30  41  24
  12  29  40  25  38  31
-------Change to start from (1,1)--------
   1  46  13  42  15  38
  12  43  48  39  28  41
  47   2  45  14  37  16
  44  11   4  27  40  29
   3   8  21  30  17  36
  22   5  10  33  26  31
   9  20   7  24  35  18
   6  23  34  19  32  25

队列

Java

import java.util.LinkedList;
import java.util.Queue;

class Point{
    int x;
    int y;
}

public class Main {
   

    private static int max = 101;
    private static int[][] board = new int[max][max];//下标从1开始
    private static int startX, startY;
    private static int[] dx = {-2, -1, 1, 2, -2, -1, 2, 1};
    private static int[] dy = {-1, -2, -2, -1, 1, 2, 1, 2};
    private static int m = 8;//行
    private static int n = 6;//列


    public static void main(String[] args) {
        startX = 2;
        startY = 2;

        int number = 1;
        board[startX][startY] = 1;

        backtrack(startX, startY, number);
    }


    private static void backtrack(int x, int y, int num) {
        //已经走完棋盘中所有的点
        if (num == n * m && isNextStepStartPoint(x, y)) {
            print(n, m);
            System.exit(1);
        }else {
            Queue<Point> pointQueue = new LinkedList<>();
            int minStep = 8;
            for(int i=0; i<8; i++){
                int pointX = x + dx[i];
                int pointY = y + dy[i];

                if(isNextStepOk(pointX, pointY)){
                    Point t = new Point();
                    t.x = pointX;
                    t.y = pointY;

                    int tmpStep = nextPossibleSteps(pointX, pointY);
                    if(tmpStep <= minStep)
                    {
                        minStep = tmpStep;
//                        ((LinkedList<Point>) pointQueue).add(0, t);
                        ((LinkedList<Point>) pointQueue).addFirst(t);
                    }else
                        pointQueue.add(t);
                }
            }

            while(!pointQueue.isEmpty()){
                Point point = pointQueue.poll();
                board[point.x][point.y] = num+1;
                backtrack(point.x, point.y, num+1);
                board[point.x][point.y] = 0;
            }
        }
    }

    //判断下一步是否回到起点
    private static boolean isNextStepStartPoint(int x, int y) {
        for (int i = 0; i < 8; i++) {
            if (x + dx[i] == startX && y + dy[i] == startY)
                return true;
        }

        return false;
    }

    private static void print(int n, int m) {
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++)
                System.out.print(String.format("%4d", board[i][j]));

            System.out.println();
        }

        if(board[1][1] != 1){
            System.out.println("-------Change to start from (1,1)--------");
            int tmpStart = board[1][1];
            for(int i=1; i<=m; i++)
                for(int j=1; j<=n; j++)
                    if(board[i][j] > tmpStart)
                        board[i][j] = board[i][j]-tmpStart+1;
                    else if(board[i][j] < tmpStart)
                        board[i][j] = board[i][j]+m*n-tmpStart+1;
                    else
                        board[i][j] = 1;
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++)
                System.out.print(String.format("%4d", board[i][j]));

            System.out.println();
        }
    }

    //参数x,y 表示棋盘的位置
    //检测(x,y) 对应位置在棋盘中是否合法
    private static boolean isNextStepOk(int x, int y) {
        if (x < 1 || y < 1 || x > m || y > n || board[x][y] != 0)
            return false;
        else
            return true;

    }

    //该处有效的下一步有多少种
    private static int nextPossibleSteps(int x, int y){
        int steps = 0;
        for(int i=0; i<8; i++){
            if(isNextStepOk(x+dx[i], y+dy[i]))
                steps++;
        }

        return steps;
    }

}

Output

  37  22  13   2  35  24
  12   1  36  23  14   3
  21  38  11  48  25  34
  10  45  32  39   4  15
  31  20  47  16  33  26
  46   9  44  27  40   5
  19  30   7  42  17  28
   8  43  18  29   6  41
-------Change to start from (1,1)--------
   1  34  25  14  47  36
  24  13  48  35  26  15
  33   2  23  12  37  46
  22   9  44   3  16  27
  43  32  11  28  45  38
  10  21   8  39   4  17
  31  42  19   6  29  40
  20   7  30  41  18   5

优先队列

Java

import java.util.Comparator;
import java.util.PriorityQueue;

class Point{
    int x;
    int y;
    int nextPossibleSteps;//表示当前点的下一位置有多少种走法;走法少的优先考虑
    int currentToMidLength;//表示当前点与中心点的距离;距离中心点远的优先考虑
}

//class Point implements Comparable {
   
//    int x;
//    int y;
//    int nextPossibleSteps;//表示当前点的下一位置有多少种走法;走法少的优先考虑
//    int currentToMidLength;//表示当前点与中心点的距离;距离中心点远的优先考虑
//
//    public int compareTo(Object o) {
   
//        Point point=(Point) o;
//        int result = Integer.compare(nextPossibleSteps, point.nextPossibleSteps);//先按 下次可能步数 由小到大 排列
//        if(result == 0){
   
//            result = Integer.compare(point.currentToMidLength, currentToMidLength);//下次可能步数 相同时,再按 与中心点距离 由大到小 排列
//        }
//        return result;
//    }
//
//}

public class Main {
   

    private static int max = 101;
    private static int[][] board = new int[max][max];
    private static int startX, startY;
    private static 
  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值