骑士走棋盘问题

 
话说这个题是到目前为止最让我崩溃的一个,并不是说他多难,而是这个问题的解决过程让我很忧伤~~这个问题一共花了近三天时间(囧),第一天上午刚拿到替就匆匆忙忙开做,结果后来发现答非所问,下午终于把这个问题要求做啥,怎么做搞明白了,之后自己想算法,结果越想越感觉复杂,很受打击,拿着解法看起来,就是那几行蓝字部分,看完后的感觉四个字:不知所云,然后~这题就被扔到一边了...第二天上午,硬着头皮把示例程序搞明白了,然后就继续敲程序,结果写了N个,总是有这样那样的问题,感觉很抓狂,第三天从早上开始一直检查写的那个程序,一直到晚上都没发现错误的地方,一怒之下,拿着beyond compare一个一个字的比较终于找到了出错的原因,原来某个位置的Y被错误的写成了X,悲催的,废话这么多,步入正题~~~
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
说明
骑士旅游(Knight tour)在十八世纪初倍受数学家与拼图迷的注意,它什么时候被提出已不可考,骑士的走法为西洋棋的走法,骑士可以由任意位置出发,它要如何走完所有的位置?
骑士走法简介:  首先,国际象棋的棋盘如下 
图片
骑士的走法为:先横或竖1或2格,再竖或横2或1格,没有中国象棋蹩脚的限制。 如:从图中的(a,1)格跳到(b,3)或(c,2)格。看gif走法图应该更形象一些:
图片 
解法:骑士的走法,基本上可以使用递回来解决,但是纯綷的递回在维度大时相当没有效率,一个聪明的解法由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 }

 

posted @ 2014-09-13 22:04  xxNote  阅读(1193)  评论(0编辑  收藏  举报