騎士走棋盤


問題陳述:

  騎士游歷(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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM