您的位置:首页 > 职场人生

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

2007-09-28 22:36 232 查看
问题:
在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个节点所需要的总的步数和天数都算了,进行比较,取出最小的就可以了。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: