問題陳述:
騎士游歷(Knight tour)在十八世紀初備受數學家與拼圖迷的注意,究竟它是什么時候被提出已不可考。騎士的走法為國際象棋的走法,類似中國象棋的馬,騎士可以由任意一個位置出發,他如何走完所有的位置?
問題解法:
騎士的走法,基本上可以用遞歸的方法來解決,但是純粹的遞歸在維度大時相當沒有效率。一個聰明的解法由J.C.Warnsdorff在1823年提出,簡單的說,先將最難的位置走完,接下來的路就是寬廣,騎士所要走的下一步:為下一步再做選擇時,所能走的步數最少的一步。使用這個方法,在不使用遞歸的情況下,可以有較高的幾率找出走法(有時可能也找不到走法)。
代碼詳解:
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int pos[8][8] = {0}; 7 8 int travel(int, int); 9 10 int main() 11 { 12 int i, j, startX, startY; 13 printf("Please input a starting point: "); 14 scanf("%d%d", &startX, &startY); 15 if(travel(startX, startY)) { 16 printf("Travel finished\n"); 17 }else { 18 printf("Travel failed\n"); 19 } 20 for(i=0; i<8; i++) { 21 for(j=0; j<8; j++) { 22 printf("%2d ", pos[i][j]); 23 } 24 printf("\n"); 25 } 26 return 0; 27 } 28 29 int travel(int x, int y) { 30 int i, j, k, l, m; 31 int tmpX, tmpY; 32 int count, min, tmp; 33 34 //騎士可走的八個方向(順時針) 35 int ktmoveX[8] = {1, 2, 2, 1, -1, -2, -2, -1}; 36 int ktmoveY[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 37 38 //下一步坐標 39 int nextX[8] = {0}; 40 int nextY[8] = {0}; 41 42 //記錄每個方向的出路的個數 43 int exists[8] = {0}; 44 45 //起始用1標記位置 46 i = x; 47 j = y; 48 pos[i][j] = 1; 49 50 //遍歷棋盤 51 for(m=2; m<=64; m++) { 52 //初始化八個方向出口個數 53 for(l=0; l<8; l++) { 54 exists[l] = 0; 55 } 56 l = 0; //計算可走方向 57 58 //試探八個方向 59 for(k=0; k<8; k++) { 60 tmpX = i + ktmoveX[k]; 61 tmpY = j + ktmoveY[k]; 62 //邊界 跳過 63 if(tmpX<0 || tmpY<0 || tmpX>7 || tmpY>7) { 64 continue; 65 } 66 //可走 記錄 67 if(pos[tmpX][tmpY] == 0) { 68 nextX[l] = tmpX; 69 nextY[l] = tmpY; 70 l++; //可走方向加1 71 } 72 } 73 count = l; 74 //無路可走 返回 75 if(count == 0) { 76 return 0; 77 //一個方向可走 標記 78 }else if(count == 1) { 79 min = 0; 80 //找出下個位置出路個數 81 }else { 82 for(l=0; l<count; l++) { 83 for(k=0; k<8; k++) { 84 tmpX = nextX[l] + ktmoveX[k]; 85 tmpY = nextY[l] + ktmoveY[k]; 86 if(tmpX<0 || tmpY<0 || tmpX>7 || tmpY>7) { 87 continue; 88 } 89 if(pos[tmpX][tmpY] == 0) { 90 exists[l]++; 91 } 92 } 93 } 94 //找出下個位置出路最少的方向 95 min = 0; 96 tmp = exists[0]; 97 for(l=0; l<count; l++) { 98 if(exists[l] < tmp) { 99 tmp = exists[l]; 100 min = l; 101 } 102 } 103 } 104 //用序號標記走過的位置 105 i = nextX[min]; 106 j = nextY[min]; 107 pos[i][j] = m; 108 } 109 return 1; 110 }
測試效果圖:
測試數據:startX = 2, startY = 2
轉載請注明出處:http://www.cnblogs.com/michaelwong/p/4287075.html