算法设计与分析: 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 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 = 12;//行
    private static int n = 10;//列


    public static void main(String[] args) {
        //从中心位置开始,程序运行容易得到结果
        startX = 5;
        startY = 5;

        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 {
            PriorityQueue<Point> pointPriorityQueue = new PriorityQueue<>(8, pointComparator);
//            PriorityQueue<Point> pointPriorityQueue = new PriorityQueue<>(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;
                    t.nextPossibleSteps = nextPossibleSteps(pointX, pointY);
                    t.currentToMidLength = currentToMidLength(pointX, pointY);

                    pointPriorityQueue.add(t);
                }
            }

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

    private static Comparator<Point> pointComparator = new Comparator<Point>() {

        @Override
        public int compare(Point c1, Point c2) {
            int result = Integer.compare(c1.nextPossibleSteps, c2.nextPossibleSteps);//先按 下次可能步数 由小到大 排列
//            int result = result = Integer.compare(c2.nextPosToMidLength, c1.nextPosToMidLength);
            if(result == 0){
                result = Integer.compare(c2.currentToMidLength, c1.currentToMidLength);//下次可能步数 相同时,再按 与中心点距离 由大到小 排列
//                result = Integer.compare(c1.nextPosSteps, c2.nextPosSteps);
            }
            return result;

        }

    };

    //判断下一步是否回到起点
    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;
    }

    //距离棋盘中心点的距离
    private static int currentToMidLength(int x, int y){
//        int midX = 1;
//        int midY = 1;
//        int midX = m/2 - 1;
//        int midY = n/2 - 1;
        int midX = m/2;
        int midY = n/2;
//        int midX = m/2 + 1;
//        int midY = n/2 + 1;

        return (Math.abs(x-midX) + Math.abs(y-midY));
    }

}

Output

  25  50   3  60  23  48  55  44  21  46
   4  61  24  49  64  59  22  47  56  43
  51  26  63   2  69  54  65  58  45  20
  62   5  70  53  98  67 102 117  42  57
  27  52  99  68   1 118 111  66  19 104
   6  71  28  97 110 101 120 103 116  41
  29  86  73 100 119 112 115  90 105  18
  72   7  96  85  94 109 106 113  40  91
  83  30  87  74 107 114  89  92  17  78
   8  33  84  95  88  93 108  79  14  39
  31  82  35  10  75  80  37  12  77  16
  34   9  32  81  36  11  76  15  38  13
-------Change to start from (1,1)--------
   1  26  99  36 119  24  31  20 117  22
 100  37 120  25  40  35 118  23  32  19
  27   2  39  98  45  30  41  34  21 116
  38 101  46  29  74  43  78  93  18  33
   3  28  75  44  97  94  87  42 115  80
 102  47   4  73  86  77  96  79  92  17
   5  62  49  76  95  88  91  66  81 114
  48 103  72  61  70  85  82  89  16  67
  59   6  63  50  83  90  65  68 113  54
 104   9  60  71  64  69  84  55 110  15
   7  58  11 106  51  56  13 108  53 112
  10 105   8  57  12 107  52 111  14 109

分治法(规模较大时)

Java

class grid {
    int x;
    int y;
}

public class Main {

    private static int m = 20, n = 20;
    private static grid[][] link = new grid[m][];
    private static grid[] b66 = new grid[36];
    private static grid[] b68 = new grid[48];
    private static grid[] b86 = new grid[48];
    private static grid[] b88 = new grid[64];
    private static grid[] b810 = new grid[80];
    private static grid[] b108 = new grid[80];
    private static grid[] b1010 = new grid[100];
    private static grid[] b1012 = new grid[120];
    private static grid[] b1210 = new grid[120];

    public static void main(String[] args) {

        knight(m, n);

        out();
    }

    private static void knight(int mm, int nn) {
        int i, j, k;
        int m = mm;
        int n = nn;

        //循环,初始化操作
        //一定要加入该循环,进行初始化,不然b66里面全部为null
        for (i = 0; i < 36; i++) {
            b66[i] = new grid();
        }
        for (i = 0; i < 48; i++) {
            b68[i] = new grid();
        }
        for (i = 0; i < 48; i++) {
            b86[i] = new grid();
        }
        for (i = 0; i < 64; i++) {
            b88[i] = new grid();
        }
        for (i = 0; i < 80; i++) {
            b810[i] = new grid();
        }
        for (i = 0; i < 80; i++) {
            b108[i] = new grid();
        }
        for (i = 0; i < 100; i++) {
            b1010[i] = new grid();
        }
        for (i = 0; i < 120; i++) {
            b1012[i] = new grid();
        }
        for (i = 0; i < 120; i++) {
            b1210[i] = new grid();
        }

        //初始化二维数组link
        for (k = 0; k < m; k++) {
            link[k] = new grid[n];
            for (i = 0; i < n; i++) {
                link[k][i] = new grid();//一定要加上该句,才能初始化,不然link里面全部为null
            }
        }

        //初始化二维数组a
        int[][] a = new int[10][];
        for (k = 0; k < 10; k++) {
            a[k] = new int[12];
        }

        Make2DArray2(link, m, n);
        Make2DArray1(a, 10, 12);

        int[][] a66 = {
                {1, 30, 33, 16, 3, 24},
                {32, 17, 2, 23, 34, 15},
                {29, 36, 31, 14, 25, 4},
                {18, 9, 6, 35, 22, 13},
                {7, 28, 11, 20, 5, 26},
                {10, 19, 8, 27, 12, 21},
        };
        for (i = 0; i < 6; i++)
            for (j = 0; j < 6; j++)
                a[i][j] = a66[i][j];
        change(6, 6, a, b66);

        int[][] a68 = {
                {1, 10, 31, 40, 21, 14, 29, 38},
                {32, 41, 2, 11, 30, 39, 22, 13},
                {9, 48, 33, 20, 15, 12, 37, 28},
                {42, 3, 44, 47, 6, 25, 18, 23},
                {45, 8, 5, 34, 19, 16, 27, 36},
                {4, 43, 46, 7, 26, 35, 24, 17}
        };
        for (i = 0; i < 6; i++)
            for (j = 0; j < 8; j++)
                a[i][j] = a68[i][j];
        change(6, 8, a, b68);
        change(8, 6, a, b86);

        int[][] a88 = {
                {1, 46, 17, 50, 3, 6, 31, 52},
                {18, 49, 2, 7, 30, 51, 56, 5},
                {45, 64, 47, 16, 27, 4, 53, 32},
                {48, 19, 8, 29, 10, 55, 26, 57},
                {63, 44, 11, 22, 15, 28, 33, 54},
                {12, 41, 20, 9, 36, 23, 58, 25},
                {43, 62, 39, 14, 21, 60, 37, 34},
                {40, 13, 42, 61, 38, 35, 24, 59}
        };
        for (i = 0; i < 8; i++)
            for (j = 0; j < 8; j++)
                a[i][j] = a88[i][j];
        change(8, 8, a, b88);

        int[][] a810 = {
                {1, 46, 37, 66, 3, 48, 35, 68, 5, 8},
                {38, 65, 2, 47, 36, 67, 4, 7, 34, 69},
                {45, 80, 39, 24, 49, 18, 31, 52, 9, 6},
                {64, 23, 44, 21, 30, 15, 50, 19, 70, 33},
                {79, 40, 25, 14, 17, 20, 53, 32, 51, 10},
                {26, 63, 22, 43, 54, 29, 16, 73, 58, 71},
                {41, 78, 61, 28, 13, 76, 59, 56, 11, 74},
                {62, 27, 42, 77, 60, 55, 12, 75, 72, 57}
        };
        for (i = 0; i < 8; i++)
            for (j = 0; j < 10; j++)
                a[i][j] = a810[i][j];
        change(8, 10, a, b810);
        change(10, 8, a, b108);

        int[][] a1010 = {
                {1, 54, 69, 66, 3, 56, 39, 64, 5, 8},
                {68, 71, 2, 55, 38, 65, 4, 7, 88, 63},
                {53, 100, 67, 70, 57, 26, 35, 40, 9, 6},
                {72, 75, 52, 27, 42, 37, 58, 87, 62, 89},
                {99, 30, 73, 44, 25, 34, 41, 36, 59, 10},
                {74, 51, 76, 31, 28, 43, 86, 81, 90, 61},
                {77, 98, 29, 24, 45, 80, 33, 60, 11, 92},
                {50, 23, 48, 79, 32, 85, 82, 91, 14, 17},
                {97, 78, 21, 84, 95, 46, 19, 16, 93, 12},
                {22, 49, 96, 47, 20, 83, 94, 13, 18, 15}
        };
        for (i = 0; i < 10; i++)
            for (j = 0; j < 10; j++)
                a[i][j] = a1010[i][j];
        change(10, 10, a, b1010);

        int[][] a1012 = {
                {1, 4, 119, 100, 65, 6, 69, 102, 71, 8, 75, 104},
                {118, 99, 2, 5, 68, 101, 42, 7, 28, 103, 72, 9},
                {3, 120, 97, 64, 41, 66, 25, 70, 39, 74, 105, 76},
                {98, 117, 48, 67, 62, 43, 40, 27, 60, 29, 10, 73},
                {93, 96, 63, 44, 47, 26, 61, 24, 33, 38, 77, 106},
                {116, 51, 94, 49, 20, 23, 46, 37, 30, 59, 34, 11},
                {95, 92, 115, 52, 45, 54, 21, 32, 35, 80, 107, 78},
                {114, 89, 50, 19, 22, 85, 36, 55, 58, 31, 12, 81},
                {91, 18, 87, 112, 53, 16, 57, 110, 83, 14, 79, 108},
                {88, 113, 90, 17, 86, 111, 84, 15, 56, 109, 82, 13}
        };
        for (i = 0; i < 10; i++)
            for (j = 0; j < 12; j++)
                a[i][j] = a1012[i][j];
        change(10, 12, a, b1012);
        change(12, 10, a, b1210);
    }

    //二维数组的构造
    private static void Make2DArray1(int[][] a, int m, int n) {
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                a[i][j] = 0;
    }

    private static void Make2DArray2(grid[][] link, int m, int n) {
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++) {
                link[i][j].x = 0;
                link[i][j].y = 0;
            }
    }

    //change用于将读入的基础棋盘的Hamilton回路转化为网格数据
    private static void change(int m, int n, int[][] a, grid[] b) {
        int i, j, k = m * n;
        if (m < n) {
            for (i = 0; i < m; i++)
                for (j = 0; j < n; j++) {
                    int p = a[i][j] - 1;
                    b[p].x = i;
                    b[p].y = j;
                }
        } else {
            for (i = 0; i < m; i++)
                for (j = 0; j < n; j++) {
                    int p = a[j][i] - 1;
                    b[p].x = i;
                    b[p].y = j;
                }
        }
    }

    private static void out() {
        int i, j, k, x, y, p;
        int[][] a;
        a = new int[m][];
        for (k = 0; k < m; k++) {
            a[k] = new int[n];
        }
        Make2DArray1(a, m, n);
        if (comb(m, n, 0, 0)) return;
        for (i = 0; i < m; i++)
            for (j = 0; j < n; j++)
                a[i][j] = 0;
        i = 0;
        j = 0;
        k = 2;
        a[0][0] = 1;
        System.out.print("  (0,0) ");
//        System.out.print("(0,0) ");
        for (p = 1; p < m * n; p++) {
            x = link[i][j].x;
            y = link[i][j].y;
            i = x / n;
            j = x % n;
            if (a[i][j] > 0) {
                i = y / n;
                j = y % n;
            }
            a[i][j] = k++;
            System.out.print(String.format("%8s", "(" + i + "," + j + ") "));
//            System.out.print("(" + i + "," + j + ") ");
            if ((k - 1) % n == 0)
                System.out.println();
        }
        System.out.println();
        for (i = 0; i < m; i++) {
            for (j = 0; j < n; j++)
                System.out.print(String.format("%4d", a[i][j]));
//                System.out.print(a[i][j] + " ");
            System.out.println();
        }
    }

    //分治法的主体由如下算法 comb 给出
    private static boolean comb(int mm, int nn, int offx, int offy) {
        int mm1, mm2, nn1, nn2;
        int[] x = new int[8];
        int[] y = new int[8];
        int[] p = new int[8];
        if (odd(mm) || odd(nn) || mm - nn > 2 || nn - mm > 2 || mm < 6 || nn < 6) return true;
        if (mm < 12 || nn < 12)//基础解
        {
            base_answer(mm, nn, offx, offy);
            return false;
        }
        mm1 = mm / 2;
        if (mm % 4 > 0) mm1--;
        mm2 = mm - mm1;
        nn1 = nn / 2;
        if (nn % 4 > 0) nn1--;
        nn2 = nn - nn1;
        //分割步
        comb(mm1, nn1, offx, offy);
        comb(mm1, nn2, offx, offy + nn1);
        comb(mm2, nn1, offx + mm1, offy);
        comb(mm2, nn2, offx + mm1, offy + nn1);
        //合并步
        x[0] = offx + mm1 - 1;
        y[0] = offy + nn1 - 3;
        x[1] = x[0] - 1;
        y[1] = y[0] + 2;
        x[2] = x[1] - 1;
        y[2] = y[1] + 2;
        x[3] = x[2] + 2;
        y[3] = y[2] - 1;
        x[4] = x[3] + 1;
        y[4] = y[3] + 2;
        x[5] = x[4] + 1;
        y[5] = y[4] - 2;
        x[6] = x[5] + 1;
        y[6] = y[5] - 2;
        x[7] = x[6] - 2;
        y[7] = y[6] + 1;
        for (int i = 0; i < 8; i++)
            p[i] = pos(x[i], y[i], n);
        for (int i = 1; i < 8; i += 2) {
            int j1 = (i + 1) % 8, j2 = (i + 2) % 8;
            if (link[x[i]][y[i]].x == p[i - 1]) link[x[i]][y[i]].x = p[j1];
            else link[x[i]][y[i]].y = p[j1];
            if (link[x[j1]][y[j1]].x == p[j2]) link[x[j1]][y[j1]].x = p[i];
            else link[x[j1]][y[j1]].y = p[i];
        }
        return false;
    }

    //odd函数
    private static boolean odd(int x) {
        if (x % 2 == 0) return false;
        else return true;
    }

    //base_answer是根据基础解构造子棋盘的结构化的Hamilton回路

    private static void base_answer(int mm, int nn, int offx, int offy) {
        if (mm == 6 && nn == 6) build(mm, nn, offx, offy, n, b66);
        if (mm == 6 && nn == 8) build(mm, nn, offx, offy, n, b68);
        if (mm == 8 && nn == 6) build(mm, nn, offx, offy, n, b86);
        if (mm == 8 && nn == 8) build(mm, nn, offx, offy, n, b88);
        if (mm == 8 && nn == 10) build(mm, nn, offx, offy, n, b810);
        if (mm == 10 && nn == 8) build(mm, nn, offx, offy, n, b108);
        if (mm == 10 && nn == 10) build(mm, nn, offx, offy, n, b1010);
        if (mm == 10 && nn == 12) build(mm, nn, offx, offy, n, b1012);
        if (mm == 12 && nn == 10) build(mm, nn, offx, offy, n, b1210);
    }

    //实质性的构造由算法build完成
    private static void build(int m, int n, int offx, int offy, int col, grid[] b) {
        int i, p, q, k = m * n;
        for (i = 0; i < k; i++) {
            int x1 = offx + b[i].x, y1 = offy + b[i].y;
            int x2 = offx + b[(i + 1) % k].x, y2 = offy + b[(i + 1) % k].y;
            p = pos(x1, y1, col);
            q = pos(x2, y2, col);
            link[x1][y1].x = q;
            link[x2][y2].y = p;

        }
    }

    //pos用于表示计算棋盘方格的编号,棋盘方格各行从上到下,各列从左到右依次编号为0,1....,mn-1
    private static int pos(int x, int y, int col) {
        return col * x + y;
    }
}

Output

  (0,0)   (2,1)   (4,0)   (6,1)   (8,0)   (9,2)   (7,1)   (9,0)   (8,2)   (9,4)   (8,6)   (9,8)   (7,9)   (8,7)   (9,9)   (7,8)   (9,7)  (10,9)  (11,7)  (13,6) 
 (14,4)  (15,2)  (13,3)  (14,5)  (12,6)  (11,4)  (13,5)  (14,7)  (16,6)  (15,4)  (16,2)  (17,4)  (15,3)  (14,1)  (16,0)  (17,2)  (16,4)  (14,3)  (15,5)  (13,4) 
 (14,6)  (15,8)  (13,9)  (12,7)  (11,9)  (10,7)  (11,5)  (12,3)  (10,2)  (11,0)  (13,1)  (15,0)  (14,2)  (16,3)  (18,4)  (17,6)  (19,5)  (18,3)  (19,1)  (17,0) 
 (15,1)  (13,0)  (12,2)  (10,1)  (12,0)  (13,2)  (11,1)  (10,3)  (12,4)  (10,5)  (11,3)  (12,5)  (10,6)  (11,8)  (13,7)  (15,6)  (17,5)  (16,7)  (15,9)  (13,8) 
 (15,7)  (16,5)  (17,3)  (18,1)  (19,3)  (18,5)  (17,7)  (19,6)  (18,8)  (16,9)  (14,8)  (12,9)  (10,8)  (11,6)  (10,4)  (11,2)  (10,0)  (12,1)  (14,0)  (16,1) 
 (18,0)  (19,2)  (17,1)  (19,0)  (18,2)  (19,4)  (18,6)  (19,8)  (17,9)  (18,7)  (19,9)  (17,8)  (19,7)  (18,9)  (16,8)  (14,9)  (12,8) (11,10) (13,11) (15,10) 
(14,12) (16,13) (18,14) (17,16) (19,15) (18,13) (19,11) (17,10) (15,11) (13,10) (12,12) (10,11) (12,10) (13,12) (11,11) (10,13) (12,14) (10,15) (11,13) (12,15) 
(10,16) (11,18) (13,17) (15,16) (17,15) (16,17) (15,19) (13,18) (15,17) (16,15) (17,13) (18,11) (19,13) (18,15) (17,17) (19,16) (18,18) (16,19) (14,18) (12,19) 
(10,18) (11,16) (10,14) (11,12) (10,10) (12,11) (14,10) (16,11) (18,10) (19,12) (17,11) (19,10) (18,12) (19,14) (18,16) (19,18) (17,19) (18,17) (19,19) (17,18) 
(19,17) (18,19) (16,18) (14,19) (12,18) (10,19) (11,17) (13,16) (14,14) (15,12) (13,13) (14,15) (12,16) (11,14) (13,15) (14,17) (16,16) (15,14) (16,12) (17,14) 
(15,13) (14,11) (16,10) (17,12) (16,14) (14,13) (15,15) (13,14) (14,16) (15,18) (13,19) (12,17) (11,19) (10,17) (11,15) (12,13) (10,12)  (9,10)  (8,12)  (9,14) 
 (8,16)  (9,18)  (7,19)  (8,17)  (9,19)  (7,18)  (9,17)  (8,19)  (6,18)  (4,19)  (2,18)  (0,19)  (1,17)  (3,16)  (4,14)  (5,12)  (3,13)  (4,15)  (2,16)  (1,14) 
 (3,15)  (4,17)  (6,16)  (5,14)  (6,12)  (7,14)  (5,13)  (4,11)  (6,10)  (7,12)  (6,14)  (4,13)  (5,15)  (3,14)  (4,16)  (5,18)  (3,19)  (2,17)  (1,19)  (0,17) 
 (1,15)  (2,13)  (0,12)  (1,10)  (3,11)  (5,10)  (4,12)  (6,13)  (8,14)  (7,16)  (9,15)  (8,13)  (9,11)  (7,10)  (5,11)  (3,10)  (2,12)  (0,11)  (2,10)  (3,12) 
 (1,11)  (0,13)  (2,14)  (0,15)  (1,13)  (2,15)  (0,16)  (1,18)  (3,17)  (5,16)  (7,15)  (6,17)  (5,19)  (3,18)  (5,17)  (6,15)  (7,13)  (8,11)  (9,13)  (8,15) 
 (7,17)  (9,16)  (8,18)  (6,19)  (4,18)  (2,19)  (0,18)  (1,16)  (0,14)  (1,12)  (0,10)  (2,11)  (4,10)  (6,11)  (8,10)  (9,12)  (7,11)   (8,9)   (6,8)   (4,9) 
  (2,8)   (0,9)   (1,7)   (3,6)   (4,4)   (5,2)   (3,3)   (4,5)   (2,6)   (1,4)   (3,5)   (4,7)   (6,6)   (5,4)   (6,2)   (7,4)   (5,3)   (4,1)   (6,0)   (7,2) 
  (6,4)   (4,3)   (5,5)   (3,4)   (4,6)   (5,8)   (3,9)   (2,7)   (1,9)   (0,7)   (1,5)   (2,3)   (0,2)   (1,0)   (3,1)   (5,0)   (4,2)   (6,3)   (8,4)   (7,6) 
  (9,5)   (8,3)   (9,1)   (7,0)   (5,1)   (3,0)   (2,2)   (0,1)   (2,0)   (3,2)   (1,1)   (0,3)   (2,4)   (0,5)   (1,3)   (2,5)   (0,6)   (1,8)   (3,7)   (5,6) 
  (7,5)   (6,7)   (5,9)   (3,8)   (5,7)   (6,5)   (7,3)   (8,1)   (9,3)   (8,5)   (7,7)   (9,6)   (8,8)   (6,9)   (4,8)   (2,9)   (0,8)   (1,6)   (0,4)   (1,2) 

   1 368 353 372 399 374 377 350 397 322 311 278 263 282 309 284 287 260 307 232
 354 371 400 375 330 351 398 323 378 349 264 281 310 285 240 261 308 233 288 259
 369   2 367 352 373 376 329 348 321 396 279 312 277 262 283 286 239 258 231 306
 366 355 370 327 344 331 324 379 384 347 276 265 280 237 254 241 234 289 294 257
   3 338 357 342 325 328 345 332 395 320 313 248 267 252 235 238 255 242 305 230
 356 365 326 337 334 343 380 385 346 383 266 275 236 247 244 253 290 295 256 293
 339   4 335 358 341 386 333 382 319 394 249 314 245 268 251 296 243 292 229 304
 364   7 340 387 336 381 360 391  16  13 274 317 250 297 246 291 270 301 226 223
   5 388   9 362 359 390  11  14 393 318 315 298 219 272 269 300 221 224 303 228
   8 363   6 389  10 361 392  17  12  15 218 273 316 299 220 271 302 227 222 225
  97  64  49  68  95  70  73  46  93  18 165 132 217 136 163 138 141 214 161 186
  50  67  96  71  26  47  94  19  74  45 118 135 164 139 194 215 162 187 142 213
  65  98  63  48  69  72  25  44 117  92 133 166 131 216 137 140 193 212 185 160
  62  51  66  23  40  27  20  75  80  43 130 119 134 191 208 195 188 143 148 211
  99  34  53  38  21  24  41  28  91 116 167 202 121 206 189 192 209 196 159 184
  52  61  22  33  30  39  76  81  42  79 120 129 190 201 198 207 144 149 210 147
  35 100  31  54  37  82  29  78 115  90 203 168 199 122 205 150 197 146 183 158
  60 103  36  83  32  77  56  87 112 109 128 171 204 151 200 145 124 155 180 177
 101  84 105  58  55  86 107 110  89 114 169 152 173 126 123 154 175 178 157 182
 104  59 102  85 106  57  88 113 108 111 172 127 170 153 174 125 156 181 176 179

Reference

王晓东《计算机算法设计与分析》(第3版)P42-43

猜你喜欢

转载自blog.csdn.net/ioio_/article/details/80959370
2-4