骑士走棋盘问题
话说这个题是到目前为止最让我崩溃的一个,并不是说他多难,而是这个问题的解决过程让我很忧伤~~这个问题一共花了近三天时间(囧),第一天上午刚拿到替就匆匆忙忙开做,结果后来发现答非所问,下午终于把这个问题要求做啥,怎么做搞明白了,之后自己想算法,结果越想越感觉复杂,很受打击,拿着解法看起来,就是那几行蓝字部分,看完后的感觉四个字:不知所云,然后~这题就被扔到一边了...第二天上午,硬着头皮把示例程序搞明白了,然后就继续敲程序,结果写了N个,总是有这样那样的问题,感觉很抓狂,第三天从早上开始一直检查写的那个程序,一直到晚上都没发现错误的地方,一怒之下,拿着beyond compare一个一个字的比较终于找到了出错的原因,原来某个位置的Y被错误的写成了X,悲催的,废话这么多,步入正题~~~
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
说明骑士旅游(Knight tour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出已不可考,骑士的走法为西洋棋的走法,骑士可以由任意位置出发,它要如何走完所有的位置?
骑士走法简介: 首先,国际象棋的棋盘如下
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
说明骑士旅游(Knight tour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出已不可考,骑士的走法为西洋棋的走法,骑士可以由任意位置出发,它要如何走完所有的位置?
骑士走法简介: 首先,国际象棋的棋盘如下
解法:骑士的走法,基本上可以使用递回来解决,但是纯綷的递回在维度大时相当没有效率,一个聪明的解法由J.C. Warnsdorff在1823年提出,简单的说,先将最难的位置走完,接下来的路就宽广了,骑士所要走的下一步,「为下一步再选择时,所能走的步数最少的一步。」,使用这个方法,在不使用递回的情况下,可以有较高的机率找出走法(找不到走法的机会也是有的)。
这几行蓝色字部分我学习的时候参考的解法说明,第一次看这个解法说明时感到很费解,去网上搜了好久发现千篇一律,竟然没有一个讲明白这个解法的。没办法,解法看不懂,只能看程序了,硬着头皮看了看,终于看懂了,说一下我对这个算法的理解:
假设棋盘为8*8=64格,我们刚走了第一个点,在这个点周围最多可以有八个点可以供我们选择,我们从这八个候选点里面选出第二点,根据什么选择第二点呢?在这八个候选点周围分别都有第三个点的候选点(叫它第二个点的出口吧,以免说起来混淆),这八个候选点中哪个点的出口数量最少就把哪个点作为第二点,然后依次用同样的方法选出剩下的点。
好了下面是代码:
刚开始的时候写的那个
1 #include <stdio.h> 2 3 #define LINE 8 4 #define ROW 8 5 #define BOOL int 6 #define TRUE 1 7 #define FALSE 0 8 9 void Show(void);//显示棋盘 10 BOOL Tour(int x, int y); 11 12 int Chessboard[LINE][ROW] = {0}; 13 int iNextX[8] = {1, 2, 2, 1, -1, -2, -2, -1};//第二点的相对X坐标 14 int iNextY[8] = {-2, -1, 1, 2, 2, 1, -1, -2};//第二点的相对Y坐标 15 int iNextXIndex[8] = {0};//iNextX中符合条件的点的索引 16 int iNextYIndex[8] = {0};//iNextY中符合条件的点的索引 17 int iCount; //下一点有几个候选点符合条件 18 int iNextNum[8] = {0};//下一点的每个候选点有几个候选点 19 20 int main(void) 21 { 22 int x, y; 23 24 printf("请输入起始点(x, y):"); 25 scanf("%d %d", &x, &y); 26 27 Chessboard[y][x] = 1; 28 29 if (Tour(x, y)) 30 { 31 printf("游历成功!\n"); 32 } 33 else 34 { 35 printf("游历失败!\n"); 36 } 37 Show(); 38 39 return 0; 40 } 41 42 BOOL Tour(int x, int y) 43 { 44 int step, i, j, tempX, tempY, iMin; 45 46 for (step=2; step<=(LINE*ROW); step++) 47 { 48 for (i=0; i<8; i++) 49 { 50 iNextNum[i] = 0; 51 } 52 53 j = 0; 54 for (i=0; i<8; i++)//查看这8个点是否符合要求 55 { 56 tempX = x + iNextX[i]; 57 tempY = y + iNextY[i]; 58 59 if (tempX>=0 && tempX<ROW && tempY>=0 && tempY<LINE \ 60 && Chessboard[tempY][tempX] == 0)//符合要求就求他的周围符合的点数 61 { 62 iNextXIndex[j] = i; 63 iNextYIndex[j] = i; 64 j++; 65 } 66 } 67 iCount = j; 68 if (iCount == 0) 69 { 70 return FALSE; 71 } 72 else if (iCount == 1) 73 { 74 j = 0; 75 } 76 else 77 { 78 79 for (i=0; i<iCount; i++)//每个符合要求的点周围有几个点 80 { 81 for (j=0; j<8; j++){ 82 tempX = x + iNextX[iNextXIndex[i]] + iNextX[j]; 83 tempY = y + iNextY[iNextYIndex[i]] + iNextY[j]; 84 if (tempX>=0 && tempX<ROW && tempY>=0 && tempY<LINE\ 85 && Chessboard[tempY][tempX] == 0) 86 { 87 iNextNum[i]++;//符合要求的每个点周围分别有几个符合要求的点 88 } 89 } 90 } 91 92 iMin = iNextNum[0]; 93 j = 0; 94 for (i=1; i<iCount; i++) 95 { 96 if (iNextNum[i] < iMin) 97 { 98 iMin = iNextNum[i]; 99 j = i; 100 } 101 } 102 103 } 104 105 //选出下一步最少的点 106 x += iNextX[iNextXIndex[j]]; 107 y += iNextY[iNextYIndex[j]]; 108 Chessboard[y][x] = step;//将第N步的值设置为N 109 110 } 111 return TRUE; 112 } 113 114 void Show(void) 115 { 116 int i, j; 117 for (i=0; i<LINE; i++) 118 { 119 for (j=0; j<ROW; j++) 120 { 121 printf("%4d", Chessboard[i][j]); 122 } 123 printf("\n"); 124 } 125 return; 126 }
后来写的(稍稍修改了一些,这个应该更清晰一些)
1 #include <stdio.h> 2 3 #define LINE 8 4 #define ROW 8 5 #define BOOL int 6 #define TRUE 1 7 #define FALSE 0 8 9 void Show(void);//显示棋盘 10 BOOL Tour(int x, int y); 11 12 int Chessboard[LINE][ROW] = {0}; 13 int iNextX[8] = {1, 2, 2, 1, -1, -2, -2, -1};//第二点的相对X坐标 14 int iNextY[8] = {-2, -1, 1, 2, 2, 1, -1, -2};//第二点的相对Y坐标 15 int iNextXReal[8] = {0};//第二点的真实X坐标 16 int iNextYReal[8] = {0};//第二点的真实Y坐标 17 int iNextRealIndex;//候选的第二点中实际选出的第二点的索引 18 int iCount; //有几个第二点符合条件 19 int iNextNextNum[8] = {0};//每个第二点有几个第三点 20 21 int main(void) 22 { 23 int x, y; 24 25 printf("请输入起始点(x, y):"); 26 scanf("%d %d", &x, &y); 27 28 if (Tour(x, y)) 29 { 30 printf("游历成功!\n"); 31 Show(); 32 } 33 else 34 { 35 printf("游历失败!\n"); 36 } 37 38 return 0; 39 } 40 41 BOOL Tour(int x, int y) 42 { 43 int step, i, j, tempX, tempY, iMin; 44 45 //第一点 46 Chessboard[y][x] = 1; 47 48 //第2点到第64点 49 for (step=2; step<=(LINE*ROW); step++) 50 { 51 for (i=0; i<8; i++) 52 { 53 iNextNextNum[i] = 0; 54 } 55 56 iCount = 0; 57 for (i=0; i<8; i++)//查看这8个点是否符合要求 58 { 59 tempX = x + iNextX[i]; 60 tempY = y + iNextY[i]; 61 62 if (tempX>=0 && tempX<ROW && tempY>=0 && tempY<LINE \ 63 && Chessboard[tempY][tempX] == 0)//符合要求就求他的周围符合的点数 64 { 65 iNextXReal[iCount] = tempX; 66 iNextYReal[iCount] = tempY; 67 iCount++; 68 } 69 } 70 71 if (iCount == 0) 72 { 73 return FALSE; 74 } 75 else if (iCount == 1) 76 { 77 iNextRealIndex = 0; 78 } 79 else 80 { 81 82 for (i=0; i<iCount; i++) 83 { 84 for (j=0; j<8; j++) 85 { 86 tempX = iNextXReal[i] + iNextX[j]; 87 tempY = iNextYReal[i] + iNextY[j]; 88 if (tempX>=0 && tempX<ROW && tempY>=0 && tempY<LINE \ 89 && Chessboard[tempY][tempX] == 0) 90 { 91 iNextNextNum[i]++;//符合要求的每个点每个第2点周围有几个符合要求第3点 92 } 93 94 } 95 } 96 97 iMin = iNextNextNum[0]; 98 iNextRealIndex = 0; 99 for (i=1; i<iCount; i++) 100 { 101 if (iNextNextNum[i] < iMin) 102 { 103 iMin = iNextNextNum[i]; 104 iNextRealIndex = i; 105 } 106 } 107 108 } 109 110 //选出下一步最少的点 111 x = iNextXReal[iNextRealIndex]; 112 y = iNextYReal[iNextRealIndex]; 113 Chessboard[y][x] = step;//第N点的值为N 114 } 115 return TRUE; 116 } 117 void Show(void) 118 { 119 int i, j; 120 for (i=0; i<LINE; i++) 121 { 122 for (j=0; j<ROW; j++) 123 { 124 printf("%4d", Chessboard[i][j]); 125 } 126 printf("\n"); 127 } 128 return; 129 }