1、4、 如何找到一条满足条件的路径。5、 如何确定这条路径是最短的。本问题的关键和难点是如何根据骑士的走法规则,找出一条最短路径。 hgfedcba|012345 67 图1:8*8的棋盘如图,建立如上的坐标系,于是每个点的位置就可以用一个有序数对来表示。如:(a,3),(b,6),(h,2)。对于任意一点的马最多有8中走法可以选择。根据马行走后行列坐标数值大小的增加和减少情况的变化,用有序数组对来表示其走法。static int bx8 = 2,1,-1,-2,-2,-1,1,2;static int by8 = 1,2,2,1,-1,-2,-2,-1;其中,bx数组与by数组下标相同的变量表
2、示一种走法。骑士在棋盘中的位置可由结构体类型typedef struct int n,m; /n 记录行数,m 记录列数 int ch;node;来表示。对于骑士的起始与终点位置可由有序对(x0,y0),(x1,y1)来表示。另外建立一个队列,typedef struct /定义顺序队列类型 node datamaxlen; int front; int rear;Sequeue;把骑士从起点到终点的每一步入队,前一步出对。二、 概要设计与数据结构选择对于所提出的关键问题,即找出从起点到终点的最短步数,这里所用到的方法是遍历起点与终点的所有路径,记录下其步数,然后比较其中最小的步数,即为最短步
3、数。1、 输入起点和终点的坐标,起点先入对;2、 按照上述的8走法分别走一步,如果到达终点,计步器加一,如果未到终点,计步器加一并入对;(所有走法均入队)3、 出对,以步骤2中的如对顺序分别把其作为新起点,重复步骤2;4、 判断是否对空,对空则以走过全部路径,对未空,重复步骤3;对空,转到步骤5;5、 比较每种路径的步数,选出最小的数值,即为最小步数。以上操作相当于对于一棵8个结点的完全树进行遍历,查找满足条件的结点,并找出这些结点中结点高度最低的结点。以上过程可由树来表示。树如图2: 图2:骑士游历的树结构如图3,先找到起点,即根节点,并进行入队操作。由起点逐次访问起点的各个子树的根节点,比
4、较是否等于终点的坐标,若相等,则保存路径长度;若不相等,则把不相等的子树的根节点进行入队操作。访问完所有子树的根节点后,进行一次出队操作;即把根节点出队。此后顺次访问队头节点的子树的根节点,即顺次访问根节点的子树的根节点的各个子树的根节点,比较是否等于终点的坐标,若相等,则保存路径长度;直到队为空为止。访问顺序如下: 图3:游历的访问顺序数据结构如下:typedef struct /骑士位置结构体 int n,m; int ch;typedef struct /顺序队列类型结构体 node datamaxlen; int front; int rear;图4:详细设计流程图三、 详细设计和编码
5、首先,对于在问题分析和任务定义中所提出的问题逐个进行解决。 定义棋盘和走法,并对其进行初始化。 int way88 表示棋盘每一点的位置,例如,way22表示第三行,第三列的坐标,way36表示第四行,第七列的坐标。因为在本实验中并没有要求骑士行走的路径,所以棋盘可不显示的定义。 对于走法,我们前面已经提到了,对于马在棋盘中的任意位置,最多有8种走法,用有序数对表示即:(2,1),(2,-1)(1,2),(1.-2)(-2,1),(-2,-1),(-1,2),(-1,-2)。故,我们可以做如下定义:所以在骑士的行走过程中,只要让骑士的位置即坐标加上或减去上述8中走法的数组表示。 对于骑士的起点
6、和终点的位置表示,根据要求位置由两个字符组成,一个是小写字母(a-h),一个是数字(1-8)。所以有如下的表示方法:int x0,y0,x1,y1; char xa,xb;x0=xa-a; x1=xb-a;其中,x0、y0表示起点坐标,x1、y1表示终点坐标,输入的xa,xb为字符,减去a,便可转换成数字。这样便可以把输入的字符坐标转换成用数字表示的坐标。在得到骑士的起点终点坐标之后,便可以把起点入队,入队函数如下所示:void add(Sequeue *S,int x,int y,int z) /入队函数 if(S-rearrear=0) S-rear+;dataS-rear.n=x;rea
7、r.m=y;rear.ch=z; else printf(errorn);这里的参数x,y,z分别表示行坐标,列坐标,和到达该坐标从起点所走的步数。它们的值分别保存在队列的n,m,ch中。在对起点进行入队之后,便可进行运动了,即骑士可以按规则(8种走法)走向下一位置。此后,在一个while循环中进行如下的操作,while循环的条件为:S-frontrear,保证在队列不为空的情况下进行循环。对于骑士的8种走法,可以通过for(i=0;ich=S-front+1.ch+1;n=x3;m=y3;stepx3y3=1;把(x3,y3)的值放入指针p指向的空间的(n,m)中,用以保存此位置;因为ch存
8、放的是从起点到该位置所走的步数,故p-即它表示的意思是从起点x3、y3所走的步数。此时并把x3y3的标记置为1,说明此位置已经被访问过了。这时便可以对x3、y3进行判断了。若p-n=x1 & p-m=y1,即比较x3、y3与终点的坐标是否相同。若相同则找到一种走法。此时定义 int a=0;int countmaxlen; counta数组的作用就是记录下每一种走法的步数;令 counta=p-ch即可。若不满足条件的话则把x3、y3入队;然后i+;重复上述操作,直到i不满足条件为止,即已经走完了8种走法;此后,进行出栈操作;判断S-front与S-rear的大小关系,若S-frontrear
9、,则进行while循环,若不满足,则跳出while循环。最后,对计数数组counta中的值进行比较,找出最小值,即为,从终点到起点的最小步数。程序如下:int min;min=count0;for(i=1;a;i+) if(mincounti) min=counti; printf(最短步数为: %dn,min);四、 上机调试1、语法错误及修正:本程序使用了循环思想和队列的数据结构,所以程序出现的语法错误主要在于队列函数的调用及变量的定义,关键字和函数名称的书写,以及一些库函数的规范使用。这些问题均可以根据编译器的警告提示,对应的将其解决。2、 逻辑问题的修改和调整:循环思想的使用虽然简化了
10、程序,但是增加了对函数循环控制的难度。在while循环中,要实现对所有路径的查找,而不能丢掉一条,也许丢掉的便是我们所需要的,这样便造成了错误。又因为我们对路径的查找使用了队列的数据结构,即对坐标进行了入队和出对的操作。所以我们可以用对空的条件作为while循环的终止条件。这样便可以无遗漏的查找起点到终点的所有路径。还有一点容易出现逻辑错误的是在何时进行入队和出对的操作。对入队的操作而言,在每一次行走后对于不满足条件的坐标均要进行入队操作。而对于出对而言,每次出队操作均在对每一步的八种走法走完之后才进行,这样便可以保证路径查找没有遗漏。3、 时间,空间性能分析:因为本算法需要用一个二维数组保存
11、每一个位置的访问状态,也需要一个一维数组保存访问到的满足条件的步数,故其空间复杂度较高,会占据较大的内存空间,其空间复杂度为O(maxlen*maxlen)。但是对于本算法而言,空间复杂度不但很高,时间复杂度也很大。由于本算法将对路径的遍历转变成了对树的遍历,需要遍历所有的路径并保存,从中找出满足条件的路径。所以无论起点和终点的位置如何,都需要进行所有的查找过程,所以对于本算法而言,时间复杂度很大,为O(8n*n)。由此可得,本算法的时间空间性能较差,由于知识的局限性,故本人无法对此算法进行优化。4、经验和体会:在刚拿到此问题时,感觉无从下手,但是经过仔细的分析,了解到,对骑士路径的查找,对八
12、子树的树的遍历算法很相像,不过要对每次遍历的结果进行判断,从而找出满足条件的结果。因此在具体解决问题时采用了树的数据结构思想,再经过完善和修改得出算法,并用程序语言实现。从这个过程中我了解到对问题从认识到建立模型,之后提出方法,修改方法,最终解决问题的过程。也使我体会到对于具体问题的解决,只要按照解决问题的过程,就不会出现盲目的情况。五、 用户使用说明本程序运行时带有提示性语句。开始时,程序会提示你输入骑士游历的起终点,输入格式为每一行都是一组开始位置和结束位置,位置由两个字符组成,一个是小写字母(a-h),一个是数字(0-7),起始位置结束位置由一个空格隔开。故输入的坐标横坐标的取值范围在(
13、a-h)之间,纵坐标的取值范围在(0-7)之间,输入起终点位置后,按回车,程序会给出从起点到终点的最短步数的值。之后,程序会提示你是否继续输入,输入y表示继续输入,输入n表示不再进行输入,即退出程序。这样便可以手动的控制输入的次数。方便查询。六、 测试结果图五:运行结果七、 附录#includestdio.h#include stdlib.h#define maxlen 100int length=0; /记录所走的步数Sequeue *setqueue() Sequeue *S; S=(Sequeue *)malloc(sizeof(Sequeue);front=0;rear=0; retu
14、rn S;void dele(Sequeue *s) /出队函数 if(s-s-rear) s-front+; else printf(void judge() /判断步数 S=setqueue(); int x0,y0,x1,y1,x3,y3,i,j; int countmaxlen+100;int a=0; int stepmaxlenmaxlen; char xa,xb; for( i=0;maxlen;datai.ch=0;请输入骑士游历的起终点:n scanf( %c,%d %c,%d,&xa,&y0,&xb,&y1); x0=xa-a; x1=xb- for( j=0;j node
15、 *p; x0=S-front+1.n; y0=S-front+1.m; for(int i=0; x3=bxi+x0; y3=byi+y0; if(x3=0 & x3 y3 stepx3y3=1; if(p-m=y1) stepx1y1=0; counta=p-ch; a+; else add(S,p-n,p-m,p-ch); dele(S); int min; min=count0; for(i=1;void main() char nn; nn=y while(nn=) judge();是否继续输入?(是,n否)n scanf( %cnn); system(pause八、 参考书目王昆仑,李红。数据结构与算法。北京:铁道工业出版社,2007年5月第一版
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1