馬踏棋盤算法(騎士周遊問題)算法
定義:將馬隨機放在國際象棋的8×8棋盤Board[0~7][0~7]的某個方格中,馬按走棋規則進行移動。要求每一個方格只進入一次,走遍棋盤上所有64個方格。數組
算法:如圖:測試
用一個二維數組來存放棋盤,假設馬兒的座標爲(x,y),那麼可供選擇的下一個位置共有8種可能。咱們所要作的,就是從0號位置開始,依次判斷新的馬兒位置是否可用,不可用的話(即馬兒已經走過該位置),則遍歷下一個可能的1號位置,直到7號位置中止,若是沒有可用位置,則進行回溯,若是回溯到了起始位置,則表示此路不通,即沒法從該位置開始遍歷整個棋盤。若是在遍歷0-7號位置的過程當中,發現有可用位置,則將該位置座標賦予(x,y)。以後,利用遞歸,再次尋找馬兒的新的跳躍位置。直到馬兒跳了64次時中止,此時,馬兒就已經將整個棋盤走過了。spa
代碼以下:3d
horse.ccode
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 #define X 5 //定義棋盤。爲測試方便,用5格棋盤。8格棋盤的時間複雜度,真的傷不起啊……期待更好的算法 6 #define Y 5 7 8 void print_chess(); 9 int next(int *x,int *y,int step); 10 int traverse(int x,int y,int count); 11 int traverse_chess(int x,int y,int tag); 12 13 int chess[X][Y]; //棋盤 14 15 int main23() 16 { 17 clock_t start,end; //記錄一下程序耗時 18 int i,j; 19 //初始化棋盤 20 for(i=0;i<X;i++) 21 { 22 for(j=0;j<Y;j++) 23 { 24 chess[i][j]=0; 25 } 26 } 27 start=clock(); 28 29 //方法一 30 chess[2][0]=1; 31 int result=traverse(2,0,2); 32 33 //方法二 34 //int result=traverse_chess(2,0,1); //也能夠使用這個方法 35 36 end=clock(); 37 if(1==result) 38 { 39 printf("ok\n"); 40 print_chess(); 41 printf("共耗時:%f\n",(double)(end-start)/CLOCKS_PER_SEC); 42 } 43 else 44 { 45 printf("此路不通,馬兒沒法踏遍全部棋格!\n"); 46 } 47 return 0; 48 } 49 50 /* 51 判斷下一個結點位置是否可用 52 當前結點位置(x,y) 53 step:下一個結點位置編號 54 */ 55 int next(int *x,int *y,int step) 56 { 57 // printf("%d\n",step); 58 switch(step) 59 { 60 case 0: 61 if(*y+2<=Y-1 && *x-1>=0 && chess[*x-1][*y+2]==0) 62 { 63 *y+=2; 64 *x-=1; 65 return 1; 66 } 67 break; 68 case 1: 69 if(*y+2<=Y-1 && *x+1<=X-1 && chess[*x+1][*y+2]==0) 70 { 71 *y+=2; 72 *x+=1; 73 return 1; 74 } 75 break; 76 case 2: 77 if(*y+1<=Y-1 && *x+2<=X-1 && chess[*x+2][*y+1]==0) 78 { 79 *y+=1; 80 *x+=2; 81 return 1; 82 } 83 break; 84 case 3: 85 if(*y-1>=0 && *x+2<=X-1 && chess[*x+2][*y-1]==0) 86 { 87 *y-=1; 88 *x+=2; 89 return 1; 90 } 91 break; 92 case 4: 93 if(*y-2>=0 && *x+1<=X-1 && chess[*x+1][*y-2]==0) 94 { 95 *y-=2; 96 *x+=1; 97 return 1; 98 } 99 break; 100 case 5: 101 if(*y-2>=0 && *x-1>=0 && chess[*x-1][*y-2]==0) 102 { 103 *y-=2; 104 *x-=1; 105 return 1; 106 } 107 break; 108 case 6: 109 if(*y-1>=0 && *x-2>=0 && chess[*x-2][*y-1]==0) 110 { 111 *y-=1; 112 *x-=2; 113 return 1; 114 } 115 break; 116 case 7: 117 if(*y+1<=Y-1 && *x-2>=0 && chess[*x-2][*y+1]==0) 118 { 119 *y+=1; 120 *x-=2; 121 return 1; 122 } 123 break; 124 default: 125 break; 126 } 127 return 0; 128 } 129 130 /* 131 遍歷整個棋盤-方法一 132 (x,y)爲座標位置 133 count爲遍歷次數 134 */ 135 int traverse(int x,int y,int count) 136 { 137 int x1=x,y1=y; //新節點位置 138 if(count>X*Y) //已所有遍歷且可用,則返回。 139 return 1; 140 int flag,result,i; 141 for(i=0;i<8;i++) 142 { 143 flag=next(&x1,&y1,i); //尋找下一個可用位置 144 if(1==flag) 145 { 146 chess[x1][y1]=count; //新找到的結點標識可用, 147 result=traverse(x1,y1,count+1); //以新節點爲根據,再次遞歸下一個可用結點 148 if(result) //當前棋盤已所有可用 149 { 150 return 1; 151 } 152 else //新找到的結點無下一個可用位置,進行回溯 153 { 154 chess[x1][y1]=0; 155 x1=x; //結點位置也要回溯 156 y1=y; 157 } 158 } 159 } 160 return 0; 161 } 162 163 /* 164 遍歷整個棋盤-方法二 165 (x,y)爲座標位置 166 tag爲遍歷次數 167 */ 168 int traverse_chess(int x,int y,int tag) 169 { 170 int x1=x,y1=y,flag=0,count=0; 171 chess[x][y]=tag; 172 if(X*Y==tag) 173 { 174 return 1; 175 } 176 flag=next(&x1,&y1,count); 177 while(0==flag && count<=7) 178 { 179 count++; 180 flag=next(&x1,&y1,count); 181 } 182 while(flag) 183 { 184 if(traverse_chess(x1,y1,tag+1)) //若是所有遍歷完畢,則返回。 185 { 186 return 1; 187 } 188 //沒有找到下一個可用結點,則回溯 189 x1=x; 190 y1=y; 191 count++; 192 flag=next(&x1,&y1,count); 193 while(0==flag && count<=7) 194 { 195 count++; 196 flag=next(&x1,&y1,count); 197 } 198 } 199 if(flag==0) 200 { 201 chess[x][y]=0; 202 } 203 return 0; 204 } 205 206 /* 207 打印棋盤 208 */ 209 void print_chess() 210 { 211 int i,j; 212 for(i=0;i<X;i++) 213 { 214 for(j=0;j<Y;j++) 215 { 216 printf("%d\t",chess[i][j]); 217 } 218 printf("\n"); 219 } 220 }
測試結果:blog