经典游戏算法之骑士走棋盘

问题描述:中国象棋中,马可以走遍棋盘上的任何角落.国际象棋中,也同样有这样的说法:骑士可以走遍棋盘上的每个格子.现在的问题是:在一个8x8的棋盘上,从任意位置开始,骑士如何可以不重复地走完所有的位置?

 

骑士在每一步都有8种可能的下一步走法(边界上除外),为了提高效率,可以选择所要走的下一步为下一步要选择时所能走的步数最少的一步.

 

函数说明:

bool travel(int board[][SIZE],int x,int y);        //遍历函数,传入数组表示棋盘,x,y表示骑士的初始位置坐标

具体步骤:

首先记录当前位置走的次序,然后遍历棋盘,得到可能的下一跳数目,通过min函数找到最合适的下一跳,记录下一跳位置走的次序.如果能够遍历完成,返回true表示骑士不重复的走完棋盘.

int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y);//计算下一步的可能方向,传入数组表示棋盘,数组记录多个下一步可能方向,x,y为当前骑士位置坐标

具体步骤:

将所有的下一跳以坐标表示,若当前位置上下一跳的元素值为0表示未走过为一种可能方向,下一跳数组记录下一跳坐标,计数器累加,返回计数器

int min(int board[][SIZE],int *nexti,int *nextj,int count);  //从多个可能方向中找出下一方向数最少的方向

具体步骤:

在所有的可能的方向中遍历,分别计算下一跳的数目,取其中最小数目的方向,返回值表示下一跳数组的下标

 

C++代码:

  1. #include <iostream>  
  2. #include <iomanip>  
  3. #define SIZE 8  
  4. using namespace std;  
  5. bool travel(int board[][SIZE],int x,int y);          
  6. int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y);  
  7. int min(int board[][SIZE],int *nexti,int *nextj,int count);    
  8. void printBoard(int borad[][SIZE]);  
  9. int main()  
  10. {  
  11.     int start_x;  
  12.     int start_y;  
  13.     cout<<"输入初始位置"<<endl;  
  14.     cin>>start_x>>start_y;  
  15.     int board[SIZE][SIZE]={0};  
  16.     if(travel(board,start_x,start_y))cout<<"遍历成功!"<<endl;  
  17.     else cout<<"遍历失败!"<<endl;  
  18.     printBoard(board);  
  19. }  
  20. bool travel(int board[][SIZE],int x,int y)  
  21. {  
  22.     board[x][y]=1;                   //当前位置为第1次走的位置  
  23.     int nexti[SIZE]={0};  
  24.     int nextj[SIZE]={0};             //下一跳初始化  
  25.     int i=x;  
  26.     int j=y;  
  27.     int MAX=SIZE*SIZE;  
  28.     int count=0;  
  29.     for(int m=2;m<=MAX;m++)          //遍历棋盘  
  30.     {  
  31.         count=possible(board,nexti,nextj,i,j);//得到可能的下一跳数目  
  32.         if(count==0)return false;    //无可走方向,遍历失败  
  33.         int min_Direction=min(board,nexti,nextj,count);//在多个可能方向中查找下一跳方向最少的方向  
  34.         i=nexti[min_Direction];      //下一跳位置坐标  
  35.         j=nextj[min_Direction];  
  36.         board[i][j]=m;               //当前位置为第m次走的位置  
  37.     }  
  38.     return true;  
  39. }  
  40. int possible(int board[][SIZE],int *nexti,int *nextj,int x,int y)  
  41. {  
  42.     int mvi[SIZE]={-2,-1,1,2,2,1,-1,-2};    //下一跳可能的八个方向(x坐标y坐标)  
  43.     int mvj[SIZE]={1,2,2,1,-1,-2,-2,-1};  
  44.     int count=0;  
  45.     for(int i=0;i<SIZE;++i)  
  46.     {  
  47.         int tmpx=x+mvi[i];  
  48.         int tmpy=y+mvj[i];  
  49.         if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue//越界,不是可行方向  
  50.         if(board[tmpx][tmpy]==0)                  //未走过,找到一个可能方向  
  51.         {  
  52.             nexti[count]=tmpx;  
  53.             nextj[count]=tmpy;  
  54.             count++;  
  55.         }  
  56.     }  
  57.     return count;                              //返回可能的方向数  
  58. }  
  59. int min(int board[][SIZE],int *nexti,int *nextj,int count)  
  60. {  
  61.     int mvx[SIZE]={-2,-1,1,2,2,1,-1,-2};  
  62.     int mvy[SIZE]={1,2,2,1,-1,-2,-2,-1};  
  63.     int exist[SIZE]={0};                   //记录该方向的下一跳方向的数目  
  64.     int min_direction=-1;                  //初始化最小方向数的方向  
  65.     if(count==1)min_direction=0;           //只有一个可行方向  
  66.     else  
  67.     {  
  68.         for(int i=0;i<count;++i)           //在所有可行方向中遍历  
  69.         {  
  70.             for(int j=0;j<SIZE;++j)        //计算每一个方向下一跳的数目  
  71.             {  
  72.                 int tmpx=nexti[i]+mvx[j];  
  73.                 int tmpy=nextj[i]+mvy[j];  
  74.                 if(tmpx<0||tmpy<0||tmpx>SIZE-1||tmpy>SIZE-1)continue;  
  75.                 if(board[tmpx][tmpy]==0)  
  76.                 {  
  77.                     exist[i]++;  
  78.                 }  
  79.             }  
  80.         }  
  81.         int min=exist[0];                 //取其中最小数目的方向  
  82.         min_direction=0;  
  83.         for(int i=1;i<count;++i)          //此处count开始错为SIZE,一直未查出错误  
  84.                                           //exist数组只有count位不为0  
  85.         {  
  86.             if(exist[i]<min)  
  87.             {  
  88.                 min=exist[i];  
  89.                 min_direction=i;  
  90.             }  
  91.         }  
  92.     }  
  93.     return min_direction;  
  94. }  
  95. void printBoard(int board[][SIZE])  
  96. {  
  97.      for(int i=0;i<SIZE;++i)  
  98.      {  
  99.          for(int j=0;j<SIZE;++j)  
  100.          {  
  101.              cout<<setw(2)<<board[i][j]<<"  ";  
  102.          }  
  103.          cout<<endl;  
  104.      }  
  105. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值