1. 程式人生 > >《數據結構與算法分析-C語言實現》 馬蹄棋盤

《數據結構與算法分析-C語言實現》 馬蹄棋盤

efault def flag mes pan 設計 The chess 嘗試

問題描述

國際象棋的棋盤為8×8的方格棋盤。現將“馬”放在任意指定的方格中,按照“馬”走棋的規則將“馬”進行移動。要求每個方格只能進入一次,最終使得“馬”走遍棋盤的64個方格。

編寫一個C程序,實現馬踏棋盤操作,要求用1?64這64個數字標註馬移動的路徑,也就是按照求出的行走路線,將數字1,2,……64依次填入棋盤的方格中,並輸出。

問題分析

國際象棋中,“馬”的移動規則如圖1所示。

技術分享圖片

如圖1所示,圖中實心的圓圈代表“馬”的位置,它下一步可移動到圖中空心圓圈所標註的8個位置上,該規則叫做“馬走日”。但是如果“馬”位於棋盤的邊界附近,那麽它下一步可移動到的位置就不一定有8個了,因為要保證“馬”每一步都走在棋盤中。


馬踏棋盤的問題其實就是要將1,2,……,64填入到一個8×8的矩陣中,要求相鄰的兩個數按照“馬”的移動規則放置在矩陣中。

例如數字a放置在矩陣的(i,j)位置上,數字a+1只能放置在矩陣的(i-2,j+1),(i-1,j+2),(i+1,j+2),(i+2,j+1),(i+2,j-1),(i+1,j-2),(i-1,j-2),(i-2,j-1)之中的一個位置上。將矩陣填滿並輸出。

這樣在矩陣中從1,2……遍歷到64,就得到了馬踏棋盤的行走路線。因此本題的最終目的是輸出一個8*8的矩陣,在該矩陣中填有1, 2……64這64個數字,相鄰數字之間遵照“馬走日”的規則。

算法設計

解決馬踏棋盤問題的一種比較容易理解的方法是應用遞歸的深度優先搜索的思想。因為“馬”每走一步都是盲目的,它並不能判斷當前的走步一定正確,而只能保證當前這步是可走的。

“馬”走的每一步棋都是從它當前位置出發,向下一步的8個位置中的1個行走(在它下一步有8個位置可走的情況下)。因此“馬”當前所走的路徑並不一定正確,因為它可能還有剩下的可選路徑沒有嘗試馬”的行走過程實際上就是一個深度探索的過程。“探索樹”的根節點為“馬”在棋盤中的初始位置。

接下來“馬”有兩種行走方式,於是根節點派生出兩個分支。而再往下一步行走,根節點的兩個孩子又能夠分別派生出其他不同的“行走路線”分支,如此派生下去,就得到了 “馬”的所有可能的走步狀態。


可以想見,該探索樹的葉子節點只可能有兩種狀態:一是該節點不能再派生出其他的“走步”分支了,也就是“馬”走不通了;二是棋盤中的每個方格都被走到,即“馬”踏遍棋盤。於是從該探索樹的根節點到第二種情況的葉節點構成的路徑,就是馬踏棋盤的行走過程。

如何才能通過搜索這棵探索樹,找到這條馬踏棋盤的行走路徑呢?可以采用深度優先搜索的方法以先序的方式訪問樹中的各個節點,直到訪問到葉節點。

如果葉節點是第二種情況的葉節點,則搜索過程可以結束,因為找到了馬踏棋盤的行走路徑;如果葉節點為第一種情況的葉節點,即走不通了,則需要返回到上一層的節點,順著該節點的下一條分支 繼續進行深度優先搜索下去。

因此在設計“馬踏棋盤”的算法時可以借鑒圖的深度優先遍歷算法和二叉樹的先序遍歷算法。但是在這裏並不需要真正地構建這樣一棵探索樹,只需要借用探索樹的思想。

在實際的操作過程中,所謂的探索樹實際就是深度優先搜索的探索路徑,每個節點實際就是當前的棋盤狀態,而所謂的葉節點或者是在當前棋盤狀態下,“馬”無法再進行下一步行走;或者是馬踏棋盤成功。

完整程序

備註:因為程序涉及深度搜索,運行中葉節點不能再派生出其他的“走步”分支時,也就是“馬”走不通了,則返回上一節點,比較復雜,運行較慢。(一般需要一分鐘左右出現結果,請耐心等待。)

#include <stdio.h>
#define X 8
#define Y 8
int chess[X][Y];
int nextxy(int *x, int *y, int count)  /*找到基於x,y位置的下一個可走的位置*/
{
    switch(count)
    {
        case 0:
            if(*x+2<=X-1 && *y-1>=0 && chess[*x+2][*y-1]==0)
            {
                *x=*x+2;
                *y=*y-1;
                return 1;
            }
            break;
        case 1:
            if(*x+2<=X-1 && *y+1<=Y-1 && chess[*x+2][*y+1]==0)
            {
                *x=*x+2;
                *y=*y+1;
                return 1;
            }
            break;
        case 2:
            if(*x+1<=X-1 && *y-2>=0 && chess[*x+1][*y-2]==0)
            {
                *x=*x+1;
                *y=*y-2;
                return 1;
            }
            break;
        case 3:
            if(*x+1<=X-1 && *y+2<=Y-1 && chess[*x+1][*y+2]==0)
            {
                *x=*x+1;
                *y=*y+2;
                return 1;
            }
            break;
        case 4:
            if(*x-2>=0 && *y-1>=0 && chess[*x-2][*y-1]==0)
            {
                *x=*x-2;
                *y=*y-1;
                return 1;
            }
            break;
        case 5:
            if(*x-2>=0 && *y+1<=Y-1 && chess[*x-2][*y+1]==0)
            {
                *x=*x-2;
                *y=*y+1;
                return 1;
            }
            break;
        case 6:
            if(*x-1>=0 && *y-2>=0 && chess[*x-1][*y-2]==0)
            {
                *x=*x-1;
                *y=*y-2;
                return 1;
            }
            break;
        case 7:
            if(*x-1>=0 && *y+2<=Y-1 && chess[*x-1][*y+2]==0)
            {
                *x=*x-1;
                *y=*y+2;
                return 1;
            }
            break;
        default:
            break;
    }
    return 0;
}
int TravelChessBoard(int x, int y, int tag)  /*深度優先搜索地"馬踏棋盤"*/
{
    int x1=x, y1=y, flag=0, count=0;
    chess[x][y]=tag;
    if(tag == X*Y)
    {
        return 1;
    }
    flag=nextxy(&x1, &y1, count);
    while(flag==0 && count<7)
    {
        count=count+1;
        flag=nextxy(&x1, &y1, count);
    }
    while(flag)
    {
        if(TravelChessBoard(x1, y1, tag+1))
            return 1;
        x1=x;
        y1=y;
        count=count+1;
        flag=nextxy(&x1, &y1, count);  /*尋找下一個(x,y)*/
        while(flag==0 && count<7)
        {  /*循環地尋找下一個(x,y)*/
            count=count+1;
            flag=nextxy(&x1, &y1, count);
        }
    }
    if(flag == 0)
        chess[x][y]=0;
    return 0;
}
int main()
{
    int i, j;
    for(i=0; i<X; i++)
        for(j=0; j<Y; j++)
            chess[i][j]=0;
    if(TravelChessBoard(2, 0, 1))
    {
        for(i=0; i<X; i++)
        {
            for(j=0; j<Y; j++)
                printf("%-5d", chess[i][j]);
            printf("\n");
        }
        printf("The horse has travelled the chess borad\n");
    }
    else
        printf("The horse cannot travel the chess board\n");
    return 0;
}

運行結果:

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

《數據結構與算法分析-C語言實現》 馬蹄棋盤