【問題描述】 在一個具有8×8個方格的國際象棋盤上,從棋盤的任何一個方格 開始,讓馬按照允許的走步規則(L形走法)走遍所有方格,每個方格 至少並且只准走過一次。試設計一個算法實現這個有趣的問題。
【基本要求】 將馬隨機放在棋盤的某個方格中,根據J.C.Warnsdorff提出的規則 來進行遍歷。編制非遞歸程序,求出馬的行走路線,輸出所走各步的 位置。
【測試數據】 由用戶自行指定一個馬的起始位置(i, j), 0≤i, j≤7。
【實現提示】 (1)棋盤用 8×8的二維數組表示。 (2)當馬位於位置(i, j)時,可以走到下列8個位置之一:(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)。 但是,如果(i,j)靠近棋盤的邊緣,上述有些位置可能超出棋盤范圍, 成為不允許的位置。8個可能位置的位移量可以用兩個一維數組imove[8] 和jmove[8]來存儲。
(3)根據J.C.Warnsdorff提出的規則來設計算法。該規則是在所有 可走步的(尚未走過的)方格中,馬只能走向這樣一個方格:從該方格 出發,馬可走步的方格數為最少,如果可走步的方格數相等,則從馬的 當前位置來看,方向序號小的優先。 (4)采用Warnsdorff規則在大多數情況下能夠實現遍歷,但並不能 確保成功。
【選作內容】 (1)按求出的行走路線,將數字1, 2, 3,…,64依次填入一個8×8的方 陣,輸出之。 (2)在不考慮Warnsdorff規則的情況下,求出從某一起點出發的多 條以至全部行走路線。
允許我直接貼代碼了
1 #include"queue.h" 2 struct point { 3 int x;//馬的x方向 4 int y;//馬的y方向 5 }; 6 7 typedef struct Queue{ 8 struct point queue[MaxQueueSize]; 9 int front;//頭指針 10 int rear;//尾指針 11 int tag;//設置標記位 12 }SeqCQueue; 13 14 //初始化隊列操作 15 void QueueInitiate(SeqCQueue *Q){ 16 Q->front=0; 17 Q->rear=0; 18 Q->tag=0; 19 } 20 21 //判斷隊列是否為空 22 int QueueNotEmpty(SeqCQueue Q){ 23 if(Q.front==Q.rear&&Q.tag==0) 24 return 0; 25 else 26 return 1; 27 } 28 29 //入隊操作 30 void QueueAppend(SeqCQueue *Q,point x){ 31 if(Q->tag==1&&Q->front==Q->rear){ 32 printf("隊列已滿,無法插入!\n"); 33 }else { 34 Q->queue[Q->rear]=x; 35 Q->rear=(Q->rear+1)%MaxQueueSize; 36 Q->tag=1; 37 } 38 } 39 40 //出隊操作 41 void QueuePop(SeqCQueue *Q,point *d){ 42 if(Q->tag==0&&Q->front==Q->rear){ 43 printf("隊列已空,無元素可以出隊列!\n"); 44 }else { 45 *d=Q->queue[Q->front]; 46 Q->front=(Q->front+1)%MaxQueueSize; 47 Q->tag=0; 48 } 49 } 50 51 #include<stdio.h> 52 #include<string.h> 53 #define MaxQueueSize 64 54 #include "queue.h" 55 #define MAXN 8 56 57 SeqCQueue Q; 58 59 int m,n; 60 int step;//記錄馬走的步數 61 int map[MAXN][MAXN];//8*8的國際象棋棋盤 62 int dir[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};//馬理論上所能走全部的位置 63 64 65 //求出該位置的馬所能走的步數 66 int _step(int x,int y){ 67 int i,xi,yi; 68 int count=0; 69 for( i=0;i<8;i++){ 70 xi=x+dir[i][0]; 71 yi=y+dir[i][1]; 72 //邊界條件以及!map[xi][yi]表示未走過的位置 73 if(xi>=0&&xi<=MAXN-1&&yi>=0&&yi<=MAXN-1&&!map[xi][yi]) 74 count++; 75 } 76 return count; 77 } 78 79 int BFS(point s) 80 { 81 int i,x,y,temp; 82 QueueInitiate(&Q);//初始化隊列 83 QueueAppend(&Q,s);//入隊操作 84 point hd ; 85 int flag=0 ; 86 //當隊列非空時,進行廣度優先搜索 87 while(QueueNotEmpty(Q)) 88 { 89 QueuePop(&Q,&hd);//出隊列 90 map[hd.x][hd.y]=step++;//標記該位置已走過 91 printf("%d,%d\n",hd.x,hd.y);//輸出走過的位置 92 int minstep=10;//初始的最小步數 93 int flag=0;//標記 94 //8個方向進行搜索 95 for( i=0;i<8;i++){ 96 x=hd.x+dir[i][0]; 97 y=hd.y+dir[i][1]; 98 if(x>=0&& 99 x<=MAXN-1&&y>=0&&y<=MAXN-1&&!map[x][y]){ 100 //如果小於當前的最小步數,則讓隊列元素出隊列,並讓當前的元素入隊列 101 if(_step(x,y)<minstep){ 102 minstep=_step(x,y) ; 103 point t ,th ; 104 t.x=x,t.y=y ; 105 if(flag) QueuePop(&Q,&th) ;//如果是第一次的話,就不用出隊列了; 106 QueueAppend(&Q,t) ; 107 flag=1; 108 } 109 } 110 } 111 } 112 return step-1; 113 } 114 115 int main() 116 { 117 while(scanf("%d%d",&m,&n)!=EOF){ 118 //判斷起始位置是否合法 119 if(m<0||m>7||n<0||n>7){ 120 printf("起始位置不合法!\n\n"); 121 }else { 122 printf("\n"); 123 memset(map,0,sizeof(map));//將8*8的棋盤全部置為0 124 point start; 125 start.x=m,start.y=n; 126 step=1; 127 step=BFS(start); 128 //按求出的行走路線,將數字1, 2, 3,…,64依次填入一個8×8的方陣,輸出 129 for(int i=0;i<MAXN;i++){ 130 for(int j=0;j<MAXN;j++){ 131 printf("%-3d",map[i][j]); 132 } 133 printf("\n"); 134 } 135 printf("step=%d.\n",step); 136 printf("\n"); 137 } 138 } 139 return 0; 140 }