算法思考--------骑士走棋盘(c语言)

一、 规则说明
             骑士可以从任意一个位置出发,走法和中国象棋的"马"走法类似,"走日"。问:如何走完所有的位置
二、 解法
         可以用递归的方法解决,但是纯粹的递归在维度大时没有效率。一个聪明的解法由J.C.Warnsdorft提出:先将最难的位置走完,接下来的路就宽广了
三、 代码实现
#include <stdio.h> 
int travel(int x, int y);
int board[8][8] = {0}; //代表整个棋盘

int main(void) 
{ 
    int startx, starty; //记录起点
    int i, j; 
    printf("输入起始点:"); 
    scanf("%d %d", &startx, &starty); 

    if(travel(startx, starty)) 
	{ 
           printf("游历完成\n"); 
	} 
    else
	{ 
           printf("游历失败\n"); 
	} 

    for(i = 0; i < 8; i++) //打印
	{ 
           for(j = 0; j < 8; j++) 
		{
	           printf("%2d ", board[i][j]); 
		} 
        putchar('\n'); 
	} 
    return 0; 
} 

int travel(int x, int y) 
{ 
    int ktmove1[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; //这两行对应一个点可以走的八个方向的坐标
    int ktmove2[8] = {1, 2, 2, 1, -1, -2, -2, -1}; //
    int nexti[8] = {0}; //这两行存储的是可走的下一步的坐标
    int nextj[8] = {0}; //
    int exists[8] = {0}; //记录每个可走下一步的可走下一步个数
    int i, j, k, m, l; 
    int tmpi, tmpj; 
    int count, min, tmp; 
    i = x; 
    j = y; 
    board[i][j] = 1; //将起点坐标置为1

    for(m = 2; m <= 64; m++)//通过循环来标记2-64
	{
          for(l = 0; l < 8; l++) 
              exists[l] = 0; //这个数组是每次循环都要重复利用的,所以重置0
          l = 0; //这个l也是重复利用的
          for(k = 0; k < 8; k++) //通过循环判断一个坐标的八个方向是否可走
	     { 
                tmpi = i + ktmove1[k]; 
                tmpj = j + ktmove2[k]; 
                if(tmpi < 0 || tmpj < 0 || tmpi > 7 || tmpj > 7) //通过此来筛选是否可走
                     continue;
                if(board[tmpi][tmpj] == 0)//如果可走,就将可走的坐标存储在nexti,nextj中
		  { 
                     nexti[l] = tmpi; 
                     nextj[l] = tmpj; 
                     l++; //把下一步可走位置加一
		  } 
	   } 
         count = l; //将可走位置的数目赋值给count来进行一下判断
         if(count == 0)//没有下一步可走,就返回
	    { 
               return 0; 
	     } 
         else if(count == 1)//只有一个位置可走,就选择这一步,然后继续循环
	   { 
               min = 0; 
	    } 
         else //有多个位置可走时,判断哪一个可走位置的下一步的可走位置最少,就走这一步,意思是把
	   {  //把最困难的走了,这样接下来的空间就大了,可以走完所有位置的可能性就变大了
               for(l = 0; l < count; l++) //同时也说明这种非递归的方法不一定对于所有初始位置都能
		  {            //走遍全图,因为毕竟这种算法使用概率的原理
                      for(k = 0; k < 8; k++) 
			  { 
                              tmpi = nexti[l] + ktmove1[k];
                              tmpj = nextj[l] + ktmove2[k];
                              if(tmpi < 0 || tmpj < 0 || tmpi > 7 || tmpj > 7) 
				  { 
                                      continue; 
				  } 
                              if(board[tmpi][tmpj] == 0)
                                  exists[l]++; //记录可走位置下一步可走位置的个数
			  } 
		  } 
              tmp = exists[0]; 
              min = 0; 
              for(l = 1; l < count; l++) 
	        { 
                  if(exists[l] < tmp) //取得可走位置下一步可走位置最少的那个坐标
	            { 
                        tmp = exists[l]; 
                        min = l; 
		    } 
	        }
	   }
       i = nexti[min]; 
       j = nextj[min]; 
       board[i][j] = m; //将当前步数赋值给那个可走位置下一步可走位置最少的那个坐标
       } 

    return 1; 
} 
四、 效果展示


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值