算法-經典趣題-馬踏棋盤(又稱騎士周游)


一、問題

馬踏棋盤問題,又稱騎士漫步、,它是一個非常有趣的智力問題。馬踏棋盤問題的大意如下:

國際象棋的棋盤有8行8列共64個單元格,無論將馬放於棋盤的哪個單元格,都可讓馬踏遍棋盤的每個單元格。問馬應該怎么走才可以踏遍棋盤的每個單元格?

 

 

 

二、分析

我們來分析一下馬踏棋盤問題。在國際象棋中,馬只能走“日”字形,但是馬位於不同的位置其可以走的方向有所區別:

當馬位於棋盤中間位置時,馬可以向8個方向跳動;

當馬位於棋盤的邊或角時,馬可以跳動的方向將少於8個。

另外,為了求解最少的走法,當馬所跳向的8個方向中的某一個或幾個方向已被馬走過,那么馬也將跳至下一步要走的位置。可以使用遞歸的思想來解決馬踏棋盤問題。

我們可以使用遞歸的思想來解決馬踏棋盤問題,其操作步驟如下:

(1)從起始點開始向下一個可走的位置走一步。

(2)接着以該位置為起始,再向下一個可走的位置走一步。

(3)這樣不斷遞歸調用,直到走完64格單元格,就找到一個行走方案。

這里需要注意的是,如果在行走過程中,某個位置向8個方向都沒有可走的點,則需要退回上一步,從上一個位置的另外一個可走位置繼續遞歸調用,直至找到一個行走方案。

三、編程

package com.joshua317;

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        int i, j;
        Coordinate start = new Coordinate(0, 0);
        System.out.println("馬踏棋盤問題");
        System.out.println("請輸入馬的一個其實位置(x,y)");
        Scanner scanner = new Scanner(System.in);
        start.x = scanner.nextInt();
        start.y = scanner.nextInt();
        if (start.x < 1 || start.x > 8 || start.y < 1 || start.y > 8) {
            System.out.println("起始位置輸入有誤!END!!!");
        } else {
            for (i = 0; i < 8; i++) {
                for (j = 0; j < 8; j++) {
                    HorseChessBoard.chessBoard[i][j] = 0;
                }
            }

            start.x--;
            start.y--;
            HorseChessBoard.curstep = 1;
            HorseChessBoard.move(start);
        }
    }
}

class Coordinate {
    int x,y;
    public Coordinate (int a, int b) {
        x = a;
        y = b;
    }
}
class HorseChessBoard {
    static int[][] chessBoard = new int[8][8];
    static int curstep;
    //馬可以走的8個方向
    static Coordinate[] direction = {
            new Coordinate(-2, 1),new Coordinate(-1, 2),new Coordinate(1, 2),new Coordinate(2, 1),
            new Coordinate(2, -1),new Coordinate(1, -2),new Coordinate(-1, -2),new Coordinate(-2, -1)
    };

    public static void move(Coordinate curpos)
    {
        Coordinate next = new Coordinate(0, 0);
        int i, j;
        //判斷是否越界
        if (curpos.x < 0 || curpos.x > 7 || curpos.y < 0 || curpos.y > 7) {
            return;
        }
        //判斷是否走過
        if (chessBoard[curpos.x][curpos.y] != 0) {
            return;
        }
        //保存步數
        chessBoard[curpos.x][curpos.y] = curstep;
        curstep++;
        //如果棋盤位置都走完
        if (curstep > 64) {
            for (i = 0; i < 8; i++) {
                for (j = 0; j < 8; j++) {
                    System.out.printf("%5d", chessBoard[i][j]);
                }
                System.out.println("");
            }
            System.exit(0);
        } else {
            //8個可能的方向
            for (i = 0; i < 8; i++) {
                next.x = curpos.x + direction[i].x;
                next.y = curpos.y + direction[i].y;
                if (next.x < 0 || next.x > 7 || next.y < 0 || next.y > 7) {

                } else {
                    move(next);
                }
            }
        }
        //清除步數序號
        chessBoard[curpos.x][curpos.y] = 0;
        curstep--;
    }
}
 

執行該程序,輸入馬的一個起始位置(1,1),得到的結果如下圖所示。

 

 

 

如果輸入馬的另外一個起始位置(8,8),得到的結果如下圖所示。

 

 

四、擴展

馬踏棋盤是經典的程序設計問題之一,主要的解決方案有兩種:

一種是基於深度優先搜索的方法,另一種是基於貪婪算法的方法。

第一種基於深度優先搜索的方法是比較常用的算法,深度優先搜索算法也是數據結構中的經典算法之一,主要是采用遞歸的思想,一級一級的尋找,最后找到合適的解。

而基於貪婪的算法則是依據貪婪算法的思想設置一種標准,然后依據標准進行選擇,從而得到解,但是他不一定能夠得到最優解。

深度優先搜索屬於圖算法的一種,英文縮寫為DFS即Depth First Search.其過程簡要來說是對每一個可能的分支路徑深入到不能再深入為止,而且每個節點只能訪問一次.

貪心算法(又稱貪婪算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的局部最優解。貪心算法不是對所有問題都能得到整體最優解,但對范圍相當廣泛的許多問題他能產生整體最優解或者是整體最優解的近似解。

基於深度優先搜索的算法就是依據當前點找到下一個可能的點,然后對這個點進行深度優先搜索,然后依次遞歸,當出現條件不滿足時,退回來,采用其他的路勁進行搜索,最后肯定能夠得到對應的結果。

五、通過貪心算法實現

采用貪心算法,對路徑有目的地篩選,盡量選擇出口少的路先走,也就是對當前點的下一個落腳點(可能是8個)進行排序,優先走可走的路最少的那個點,使得走法較好。通俗來講,就是先預判下一個可能落腳點的出口數,出口數最少的先走掉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM