《程序员》2007年第九期算法擂台——骑士聚会

问题:
    在8×8的棋盘上分布着n个骑士,他们想约在某一格的中聚会,骑士每天可以像国际象棋中的马那样移动一次,如下图所示,可以从中间向8个方向移动,请你计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会,且n个人走的总步数最少,先到聚会地点的骑士可以不再移动等候其他骑士。
    从键盘输入n(0<n<=64),然后依此输入n个骑士的初始位置xi,yi(0<=xi,yi<=7)。屏幕输出以空格分隔的三个整数,分别为聚会点的x,y值,以及要走多少天。 

  因为水平还是有限,只是按照最原始的方法来解决这个问题。

  首先解决数据结构,将每个格子看成一个点。这样共有64个点(xi,yi(0<=xi,yi<=7)),定义每个棋子的位置结构。

    struct POS{
     int  x;
     int  y;

     POS  *before;

     bool Traveled;} ;

  首先考虑一个骑士从A点走到B点的问题。计算机解决这个问题只能用遍历,显然得用广度优先。每个节点获取相邻节点可以使用一个[8][2]的数组来描述{+-1,+-2},{+-2,+-1}等当前级的节点遍历完之后,再遍历下一级。B就是搜索的结束条件。把所有的可能步骤都找出来,取出最小的那个就是A到B的最短路径(最少步法)。

  考虑到棋盘是对称的,关于坐标轴对称,也关于原点对称,因此很多点经过变换,可以转化成已经求解过的点,比如(2,2)->(3,3)就可以转化成(1,1)->(2,2)的走法,此时就不用再重新遍历,直接查表就可以了。此过程中需要注意的是,在坐标轴上的点的走法与棋盘中间的不同,因为有可能越界。

//×ø±ê±ä»»£¬°üÀ¨Ðýת¡¢Æ½ÒÆ
void AxisTransform(POS &S, POS &D)
{
 //printf("[%d%d] [%d%d]/t", S.x, S.y, D.x, D.y );

 if( D.x == S.x )
 {
  swap(D.x,D.y);
  swap(S.x,S.y);
 }
 
 if( D.y == S.y && S.x > D.x )
 {
  swap(S.x,D.x);
 }


 if( float( D.y - S.y ) / ( D.x - S.x ) < 0 )
 {
  D.x = GRID_X-1 - D.x ;
  S.x = GRID_X-1 - S.x ;

  if( D < S )
  {
            swap(D,S);
  }
 }

    //ƽÒÆ
 if( !IsAtAxis(S.x, S.y) && !IsAtAxis(D.x, D.y)  )
 {
  if( S.y > 1  )
  {
   D.y = abs( D.y - S.y ) + 1 ;
   S.y = 1 ;
  }
  
  if( S.x > 1  )
  {
   D.x = abs( D.x - S.x ) + 1 ;
   S.x = 1 ;
  }
 }
 //printf("[%d%d] [%d%d]/n", S.x, S.y, D.x, D.y );
};

  n个骑士聚会,可能没有什么更好的方法了,只能用穷举。把n个骑士到64个节点所需要的总的步数和天数都算了,进行比较,取出最小的就可以了。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值