2009 英特尔® 线程挑战赛 第八题 骑士巡游

本文介绍了2009年英特尔®线程挑战赛中的骑士巡游问题,提出了一种多线程解决方案来计算马在棋盘上从给定方格出发,走过一定格数的封闭走法总数。通过递归回溯法和OpenMP并行化,显著提高了算法的效率,并使用Intel Amplifier工具进行性能分析和优化。优化措施包括展开递归、扩展棋盘大小和动态扩展内存空间等。
摘要由CSDN通过智能技术生成

2009 英特尔® 线程挑战赛—骑士巡游

邓辉   denghui0815@hotmail.com

下载源码

问题描述

骑士巡游问题是指使用国际象棋棋盘上的一个马,尝试按照马的标准走法(向右或向左移动两格,然后再向上或向下移动一格;或者向上或向下移动两格,然后再向右或向左移动一格)走过棋盘上的每一格且每格只能走一次。对于爱好旅行的骑士,游遍整个棋盘是一件很有成就感的事情。但在经济困难的时候,可能无法走遍棋盘的每个方格。因此,有闲暇的骑士就想知道从给定的起点方格出发,然后再回到这个起始方格(封闭式路线)的旅程究竟有多少种走法。

 

问题:编写一段多线程代码,用来计算马在棋盘上从给定方格出发,走过一定格数可能采用的封闭走法总数。要使用的输入文件和输出文件的名称将通过命令行指定。输入文件应详细列出要走的棋盘大小和形状、马的起点方格、要走的步数以及要在输出文件中完整打印的走法数量。执行应用程序后,输出文件应包含所要求数量的走法(要走过的棋盘方格的列表)以及一个汇总行,其中包含根据输入文件中给定的条件而得出的可能走法总数。

 

输入文件格式:输入文件应包含五行,格式如下所示:

1 行 – 一个整数,指定棋盘上的列数(纵列数)

2 行 – 一个整数,指定棋盘上的行数(横排数)

3 行 – 以代数记谱法(用一个小写字母指定列的位置,一个整数指定行的位置)表示的马的起点方格

4 行 – 一个整数,指定要走过的方格数

5 行 – 一个整数,指定要在输出文件中打印的完整走法数

 

输出文件格式:每个打印的完整走法应该是一列以代数记谱法表示的棋盘方格,每个方格占一行,从输入文件中给定的方格开始并以该方格结束。如果要走的步数指定为 8,那么打印的走法将在 9 行中列出 9 个方格(1 个起点方格和 8 个目标方格,其中最后一个目标方格就是起点方格)。在每种打印的走法后面,应打印一个空白行或其他格式的分隔行。打印完所要求数目的走法之后,应打印一个汇总行,给出合格走法的总数。

 

如果无法完成符合给定要求的走法,输出文件中应简单说明这种情况。

 

输入文件示例:

-------------------

8

8

a8

8

2

 

输出文件示例:

-------------------

a8

b6

d7

f6

h7

f8

e6

c7

a8

-------

a8

b6

d5

c3

a4

c5

e6

c7

a8

-------

 

总共有 5634 种可能的 8 步走法

 

计时:将使用“骑士巡游”应用程序的总执行时间进行计分。(要获得最准确的计时结果,提交的代码应包含用于计时并将时间打印到标准输出的计时代码,否则将使用外部秒表进行计时。)

串行算法

骑士巡游的常规解法为递归和回溯,先将棋盘的每个格子均置为0,表示未到达过,根据骑士的行走规则,如果当前骑士在格子[x,y]中,骑士的目标格子为[x-2,y-1],[x-2, y-1] , [x-1, y-2],[x-1, y+2],[x+1, y-2],[x+1, y+2],[x+2, y-1],[x+2, y+1]这八个格子中,

骑士每移动到一个格子,将该格子置为1,如果八个格子均为1,表示巡游失败,回溯到上一个格子尝试其它方向。

 

由于每次移动骑士所在位置的x坐标+y坐标的和奇偶性将发生改变,骑士由起点出发再回到起点,必然是通过偶数次移动才可完成。

 

假设骑士的巡游路线为C1 C2 C3 C4……Cn C1(n为偶数),那么取路线的中点为C(n+1)/2,存在两条由C1C(n+1)/2的路线,这两条路线没有交集即可,所以可以先通过递归和回溯的方法,取得由C1出发通过n/2次移动形成的所有路径,根据这些路径的终点进行分组,然后对每个分组内的路径两两比较,如果没有公共的格子则表示存在两条巡游路径C1 C2 C3 C4……Cn C1C1 Cn Cn-1……C3 C2 C1。通过该算法可大大降低搜索复杂度。

并行算法

    对于M*N的棋盘,最多存在(M*N- 1个分组,分组内巡游路径的检测是相互独立的,可以完全并行的执行,通过OpenMPparallel for即可将算法并行化。

串行代码:

uint64 XCheckPath(XPathArray* pPathArray, int nArray, int nStep)

{

     uint64 nPathCnt = 0;

     PUINT8 pMask =(PUINT8)scalable_calloc(sizeof(pMask[0]), nArray);

     for(int i = 0; i < nArray ; ++i)

     {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值