JAVA代码—算法基础:马走8×8棋盘问题

经典问题:给定一个8×8棋盘,马从任意位置开始,走“日”字,不重复的走完棋盘上的所有位置。

如图所示:

JAVA代码—算法基础:马走8×8棋盘问题_第1张图片

假设从坐标为(2,2)的点开始走,有8个方向可以选择。所以每次都要依据这最多8个方向进行选择。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。在处理马踏棋盘问题时,每次在至多8个可选的方向中,首先通过验证其中一个方向可以成功。贪心算法同样是试探至多的八个可能的出口,但是八个出口的排序并非按照前述的顺时针,而是按照每个可能出口的进一步出口数的递增排序,所以每次先试探的总是进一步出口较少的出口,能够给之后的出口更多的选择,因此贪心算法是比较高效的,而且它不回溯。

package com.bean.knightcruise;

import java.util.Scanner;

public class KnightCruise2 {
    /*
     * 马踏棋盘问题:(贪婪法求解) 棋盘有64个位置,“日”字走法,刚好走满整个棋盘
     * 贪婪的算法则是一步一步依据当前最优的策略,依靠每一步的局部最优,达到最终目标。但是他不一定能够得到最优解。
     * 关于马踏棋盘的基本过程:国际象棋的棋盘为8*8的方格棋盘。
     * 现将”马”放在任意指定的方格中,按照”马”走棋的规则将”马”进行移动。
     * 要求每个方格只能进入一次,最终使得”马”走遍棋盘的64个方格。
     * 如图所示,任意一个位置,“马”最多有8个方向可以跳动,所以每次都要依据这最多8个方向进行选择。
     * 
     * 贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,
     * 选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
     * 在处理马踏棋盘问题时,每次在至多8个可选的方向中,首先通过验证其中一个方向可以成功。
     * 贪心算法同样是试探至多的八个可能的出口,但是八个出口的排序并非按照前述的顺时针,
     * 而是按照每个可能出口的进一步出口数的递增排序,所以每次先试探的总是进一步出口较少的出口,
     * 能够给之后的出口更多的选择,因此贪心算法是比较高效的,而且它不回溯。
     */

    static final int[] dx = { -2, -1, 1, 2, 2, 1, -1, -2 }; // x方向的增量
    static final int[] dy = { 1, 2, 2, 1, -1, -2, -2, -1 }; // y方向的增量
    static final int N = 8;
    static int[][] chessboard = new int[N][N]; // 棋盘

    /**
     * 
     *  x,y为棋子的位置
     *  如果棋子的位置不合法,则返回一个大于8的数。 否则返回棋子的下个出路的个数
     */
    static int wayOut(int x, int y) {
        int count = 0;
        int tx, ty, i;
        // 判断是否超出棋盘边界,该位置是否已经下过
        if (x < 0 || x > 7 || y < 0 || y > 7 || chessboard[x][y] != 0) {
            return 9;
        }
        for (i = 0; i < N; i++) {
            tx = x + dx[i];
            ty = y + dy[i];
            // 如果棋子的下个出路可行,则出路数自加一次
            if (tx > -1 && tx < 8 && ty > -1 && ty < 8 && chessboard[tx][ty] == 0)
                count++;
        }
        return count;
    }

    /**
     * 按照棋子的下个出路的个数从低到高排序
     * 棋子的八个位置的数组
     */
    static void sort(Direction[] next) {
        int i, j, index;
        Direction temp = null;
        // 这里用的选择排序
        for (i = 0; i < N; i++) {
            index = i;
            for (j = i + 1; j < N; j++) {
                if (next[index].wayOutNum > next[j].wayOutNum)
                    index = j;
            }
            if (i != index) {
                temp = next[i];
                next[i] = next[index];
                next[index] = temp;
            }
        }
    }

    static void move(int x, int y, int step) {
        int i, j;
        int tx, ty;
        // 如果step==64,则说明每个棋格都走到了,现在只需要打印结果就完了
        if (step == N * N) {
            for (i = 0; i < N; i++) {
                for (j = 0; j < N; j++) {
                    System.out.printf("%3d", chessboard[i][j]);
                }
                System.out.println();
            }
            System.exit(0);
        }

        // 下一个棋子的N个位置的数组
        Direction[] next = new Direction[N];

        for (i = 0; i < N; i++) {
            Direction temp = new Direction();
            temp.x = x + dx[i];
            temp.y = y + dy[i];
            next[i] = temp;
            // 循环得到下个棋子N处位置的下个出路的个数
            next[i].wayOutNum = wayOut(temp.x, temp.y);
        }

        // 配合贪婪算法,按下个棋子的下个出路数排序后,next[0]就是下个出路数最少的那个
        sort(next);

        for (i = 0; i < N; i++) {
            tx = next[i].x;
            ty = next[i].y;
            chessboard[tx][ty] = step;
            //递归调用
            move(tx, ty, step + 1);
            /*
             * 如果上面Move()往下一步走不通,则回溯到这里 重置chessboard[tx][ty]为0,接着i++,又循环......
             */
            chessboard[tx][ty] = 0;
        }
    }

    public static void main(String[] args) {
        int i, j;
        // 初始化棋盘
        for (i = 0; i < 8; i++) {
            for (j = 0; j < 8; j++) {
                chessboard[i][j] = 0;
            }
        }
        System.out.println("请输入马起始位置坐标(0-7):");
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        // 第一步不用比较,赋值第一步
        chessboard[x][y] = 1;
        move(x, y, 2);
    }
}

运行结果:

请输入马起始位置坐标(0-7):
2
2
45 20 3 54 37 22 5 26
2 55 46 21 4 25 38 23
19 44 1 56 53 36 27 6
58 63 52 47 32 39 24 35
43 18 57 62 51 34 7 28
0 59 48 33 40 31 10 13
17 42 61 50 15 12 29 8
60 49 16 41 30 9 14 11

(完)

你可能感兴趣的:(算法分析与设计,算法)