《程序员》2007年第九期算法擂台——骑士聚会
问题:
在8×8的棋盘上分布着n个骑士,他们想约在某一格的中聚会,骑士每天可以像国际象棋中的马那样移动一次,如下图所示,可以从中间向8个方向移动,请你计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会,且n个人走的总步数最少,先到聚会地点的骑士可以不再移动等候其他骑士。
从键盘输入n(0<n<=64),然后依此输入n个骑士的初始位置xi,yi(0<=xi,yi<=7)。屏幕输出以空格分隔的三个整数,分别为聚会点的x,y值,以及要走多少天。
问题很是复杂,所以要先从特殊的简单的入手,我们先考虑一个骑士从某点到达另一点的最少天数,然后我们就可以考虑每个骑士到达指点地点自身所耗费的时间,最好,考虑棋盘上64个格子,那个是他们的聚会地点。
可见,问题最困难的地方是第一步,如何求解从某点到达另外一点的最短路径。在此我想到了吕震宇老师的关于华容道的系列blog,所以想到了用树来解决这个难题。
下面是核心代码,用以计算此匹马到地图上某点(endPoint)所用的最少天数:
其中level是每层的那条线。
好了,把源代码放上来:knightParty.rar
在8×8的棋盘上分布着n个骑士,他们想约在某一格的中聚会,骑士每天可以像国际象棋中的马那样移动一次,如下图所示,可以从中间向8个方向移动,请你计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会,且n个人走的总步数最少,先到聚会地点的骑士可以不再移动等候其他骑士。
从键盘输入n(0<n<=64),然后依此输入n个骑士的初始位置xi,yi(0<=xi,yi<=7)。屏幕输出以空格分隔的三个整数,分别为聚会点的x,y值,以及要走多少天。
○ | ○ | |||
○ |
○ | |||
★ | ||||
○ | ○ | |||
○ | ○ |
问题很是复杂,所以要先从特殊的简单的入手,我们先考虑一个骑士从某点到达另一点的最少天数,然后我们就可以考虑每个骑士到达指点地点自身所耗费的时间,最好,考虑棋盘上64个格子,那个是他们的聚会地点。
可见,问题最困难的地方是第一步,如何求解从某点到达另外一点的最短路径。在此我想到了吕震宇老师的关于华容道的系列blog,所以想到了用树来解决这个难题。
- 对于任何一个骑士来说,第一步有最多8种选择,当走到第二步时路径就会是8×8=64(这是最多的情况),第三步最多是64×8=512种,……(哇塞,这个数字增长的好恐怖啊)~!
- 通过图片我们可以看到,我在树的每一层中穿了一根线,这根线的作用就是要便利所有的可能路线,检查是否已经到达了目的地,因为他囊括了所有的可能,而且每走一步就会检查一下是否到达目的地。
- 按照以上两步可以在第一时间尽早的发现最短的时间(也即最短的路径)。
下面是核心代码,用以计算此匹马到地图上某点(endPoint)所用的最少天数:
1 public int GetMinDays(Point endPoint)
2 {
3 Dictionary<int, List<Node>> level = new Dictionary<int,List<Node>>();
4 List<Node> header = new List<Node>();
5 header.Add(new Node(startPoint.X, startPoint.Y));
6 int l = 0;
7 level.Add(l, header);
8
9 while (true)
10 {
11 foreach (Node node in level[l])
12 {
13 if (node.IsEquals(endPoint))
14 {
15 return l;
16 }
17 }
18
19
20 List<Node> tempList = new List<Node>();
21 foreach (Node node in level[l])
22 {
23
24 for (int i = 0; i < 8; i++)
25 {
26 Point nextPoint = MoveToNextPoint(node.current, i);
27 if (nextPoint != null)
28 {
29 node.children[i] = new Node(nextPoint.X, nextPoint.Y);
30 tempList.Add(node.children[i]);
31 }
32 }
33 }
34
35
36 level.Add(++l, tempList);
37 }
38 }
2 {
3 Dictionary<int, List<Node>> level = new Dictionary<int,List<Node>>();
4 List<Node> header = new List<Node>();
5 header.Add(new Node(startPoint.X, startPoint.Y));
6 int l = 0;
7 level.Add(l, header);
8
9 while (true)
10 {
11 foreach (Node node in level[l])
12 {
13 if (node.IsEquals(endPoint))
14 {
15 return l;
16 }
17 }
18
19
20 List<Node> tempList = new List<Node>();
21 foreach (Node node in level[l])
22 {
23
24 for (int i = 0; i < 8; i++)
25 {
26 Point nextPoint = MoveToNextPoint(node.current, i);
27 if (nextPoint != null)
28 {
29 node.children[i] = new Node(nextPoint.X, nextPoint.Y);
30 tempList.Add(node.children[i]);
31 }
32 }
33 }
34
35
36 level.Add(++l, tempList);
37 }
38 }
其中level是每层的那条线。
好了,把源代码放上来:knightParty.rar