《程序员》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个节点所需要的总的步数和天数都算了,进行比较,取出最小的就可以了。
在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个节点所需要的总的步数和天数都算了,进行比较,取出最小的就可以了。
相关文章推荐
- 《程序员》2007年第九期算法擂台——骑士聚会
- 《程序员》算法擂台之骑士聚会问题(c语言版) 一
- 《程序员》算法擂台之骑士聚会问题(c语言版) 二
- 《程序员》2008年第1期"算法擂台" - Cantor表解答
- 《程序员》2008年第1期"算法擂台" - Cantor表解答
- 08年第3期算法擂台,网友聚会题目的另一种解答
- 算法之骑士聚会问题
- 程序员杂志07年12月算法擂台时间表达的解答
- 《程序员》2008年第1期"算法擂台" - Cantor表解答
- 《程序员》2008年第2期"算法擂台" - 微积分习题解答
- 程序员12期算法擂台
- 2006年计算机安全发展最新趋势 – 发表于2007年程序员1期
- 程序员必须知道的10大基础实用算法及其讲解
- 在8X8的棋盘上分布着n个骑士,他们想约在某一个格中聚会。骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),请计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会
- 也谈谈数据结构和算法,说与立志当好程序员的
- 程序员如何快速准备面试中的算法
- 2007年程序员最应该知道的十件事(组图)
- 【算法设计与数据结构】为何程序员喜欢将INF设置为0x3f3f3f3f?
- 2009年9月刊《程序员》算法题之我见——思索之三