分酒问题数据结构与算法课程设计报告.docx
- 文档编号:11257787
- 上传时间:2023-02-26
- 格式:DOCX
- 页数:9
- 大小:21.38KB
分酒问题数据结构与算法课程设计报告.docx
《分酒问题数据结构与算法课程设计报告.docx》由会员分享,可在线阅读,更多相关《分酒问题数据结构与算法课程设计报告.docx(9页珍藏版)》请在冰豆网上搜索。
分酒问题数据结构与算法课程设计报告
题目:
已知有3个容量分别为3kg,5kg和8kg且没有刻度的酒瓶3kg和5kg的瓶子均装满了酒。
而8kg的瓶子为空。
现要求仅用这3个酒瓶将这些酒均分为两个4kg,并分别装入5kg和8kg的瓶子中。
一、问题分析和任务定义
此程序需要完成如下要求:
3个没有刻度的酒瓶,容量分别为3kg,5kg,和8kg,,3kg和5kg的瓶子装满了酒,8kg的瓶子为空。
不借用其他工具,将这些酒分为两个4kg,并分别装入5kg和8kg的瓶子中。
实现本程序需要解决一下几个问题:
该问题对应的模型是什么
模型建立好以后,采用什么样的存储结构
怎样建立模型
如何求解,即中心算法思想
如何将结果输出
本问题的关键在于建立模型,和中心算法思想。
模型的描述
可以把3个酒杯现在的容量当做一组状态,在求解过程中涉及状态的转化,可以用图模型求解。
把每次可分的状态抽象为一个图节点,利用图的相关知识去求解。
中心算法思想
图的初始状态为(053),最终状态为(440),本题的求解过程就是把(053)变成(440),也就是找到一条路径,路径的起始点为(053),终点为(440)。
因此可以采用图的深度优先搜索遍历。
但本题搜索的起点已经给定。
二、概要设计和数据结构的选择
设计本题算法的构思如下:
(1)为搜索除符合条件的简单路径,需要按深度优先搜索方式进行遍历。
因此,求解算法应是深度遍历算法的变形形式,因而也是递归是形式的算法。
由于要求遍历序列中的各结点按次序构成一条简单路径,因此,本算法与深度遍历算法有明显的不同:
并非任意选择的起点和访问次序都能得到解。
而本题的起点和终点是确定的。
既然要在求解过程中进行试探,则需要记录试探的中间状态;某顶点是否在当前试探路径中,已经试探的各顶点和当前试探顶点的信息。
将所用的变量及有关参数设置如下:
用邻接链表存储所得图的结构,链表用两个结构体表示,(structarc_node,structvex_node),其中每个链表的头保存在一个数组中。
用布尔数组visited[MAX_SIZE]表示各状态顶点是否在当前路径中(初始状态全为false).
用数组A存储当前路径中的个顶点。
(4)既然是试探型求解,则需要对当前顶点v0的每个邻接点进行试探(程序中用s[v0].next表示),试探由v0经s[v0].next往下是否可以得到解,每个s[v0].next都有可能成功(指现在可以放在路径上,这包括暂时的和最终的)与失败的(指状态转化不能完成),,对此应分别做不同的处理:
若试探成功,则应将s[v0].next放在路径中,。
然后再由其往下求解。
若不成功,则应恢复s[v0].next的用关信息,以使s[v0].next在试探其他路径中成为可选的试探点。
(5)为了能求出解以及所有可能的解,需要做如下的工作:
选择路径:
本题中的起点已经限定,即start_vex={053}
搜索路径:
从v往下搜索时,应依次选择v的所有不在当前路径中的邻接点往下搜索。
为此,需要有这方面的保证:
应在试探某顶点之后并在换下一个试探顶点的前恢复该顶点的有关状态,以使其重新成为可选择的顶点。
本题的模型已经抽象成了图,所以可以用邻接表来存储图。
邻接表数据类型描述如下:
typedefstructnodeexdata[i]);
给出要求的终点
for(i=0;i scanf("%d",&end[i]); 下面对邻接表和状态表的建立进行分析和说明 将顶点为number的值即s[number].vexdata的值赋给part[],调用jisuan(number)函数,依次求出顶点0的邻接点,将求出的邻接点保存到状态表中,并加入到邻接表中。 令number=number+1,重复上面的步骤,求出所有顶点的邻接点,得到一个完整的状态表和邻接表。 求顶点邻接点的过程如下: 通过两个for循环来改变酒杯的下标和比较。 for(i=0;i {for(j=0;j If(i==j)continue 先是i号酒杯与j号酒杯比较 If(i==j)continue 若i=j,则i和j是同一酒杯,无需比较和改变。 若i≠j则进行下面的操作: I=part[i]; J=full[j]-part[j]; I是i号酒杯里当前的酒,J是j号酒杯里剩余的容量 判断i号酒杯的当前容量是否小于等于j号酒杯的空余量。 若是,则将i号酒杯里德酒全部倒入j号酒杯,得到一种新的状态,调用save()函数,保存到状态表。 恢复i酒杯和j酒杯改变前的容量。 加入到邻接表中;若i号酒杯的当前容量大于j号酒杯的空余量,则将i号酒杯的酒倒入j号酒杯,直至j号酒杯满为止,得到一种新的状态,调用save()函数,保存到状态表,加入到邻接表中。 恢复i酒杯和j酒杯改变前的容量。 (注意,一定要恢复i酒杯和j酒杯改变前的容量,恢复到调用jisuan()之前的状态,这样才能求出该状态所有的邻接点。 )一次变换结束。 然后j=j+1,重复上面的步骤,直至j>=N为止。 然后是i=i+1,重复上面步骤,直至i>=N为止。 这样就把顶点number所有的邻接点都求出来了,并且加入到了状态表和邻接表中。 保存状态的过程如下: for(i=0;i<=sta;i++)作为循环控制的条件,在循环中调用compare(part[],s[i].vexdata)函数,使该状态与状态表中的状态一一比较,判断该状态是否在。 (compare()函数是比较两个数组是否相等的函数,若相等返回false,若不等返回TRUE,为本程序子函数,在此不做详细说明) 若该状态不存在,令sta++,将该状态则加入到状态表中,该状态在状态表中的下标是sta;判断该状态是否是最终状态,若是令end-vex=sta.。 同时将该状态加入到邻接表中。 若该状态存在,则仅将该状态加入到邻接表中。 creat()函数完成后,就将状态表和邻接表都建立好了。 得到状态表s[sta],状态表中的内容为: 表1状态表 S[0] 053 S[1] 503 S[2] 350 S[3] 800 S[4] 530 S[5] 323 S[6] 233 S[7] 620 S[8] 251 S[9] 602 S[10] 701 S[11] 152 S[12] 710 S[13] 143 S[14] 413 S[15] 440 S[0]为起点,S[15]为要求的状态,也就是遍历的终点。 得到邻接表: 表2邻接表 0 →→ 1 →→ 2 ∧ 1 →→ 0 →→ 3 →→ 4 ∧ 2 →→ 0 →→ 3 →→ 5 ∧ 3 →→ 1 →→ 2 ∧ 4 →→ 1 →→ 3 →→ 6 ∧ 5 →→ 0 →→ 1 →→ 2 →→ 7 ∧ 6 →→ 0 →→ 11 →→ 2 →→ 8 ∧ 7 →→ 2 →→ 3 →→ 5 →→ 9 ∧ 8 →→ 0 →→ 2 →→ 10 ∧ 9 →→ 1 →→ 3 →→ 7 →→ 11 ∧ 10 →→ 1 →→ 3 →→ 8 →→ 12 ∧ 11 →→ 0 →→ 2 →→ 9 →→ 13 ∧ 12 →→ 2 →→ 3 →→ 10 →→ 14 ∧ 13 →→ 0 →→ 1 →→ 11 →→ 15 ∧ 14 →→ 0 →→ 1 →→ 12 →→ 15 ∧ 15 →→ 2 →→ 3 →→ 13 →→ 14 ∧ 以上我们解决了状态表和邻接表的建立,下面就要进行求解了,对邻接表进行深度优先搜索,从起点{053}开始,求出所有到{440}的路径,每求出一条路径,输出。 每一条路径对应一种解法 深度优先搜苏遍历: 本程序和普通的深度优先搜素遍历有点不同,那就是起点已将给定,即{053}。 首先判断起点是否已访问过,若没有,分两种情况: 当访问的到顶点状态v==end_vex(最终状态)时,则说明已经求得一解,因此可输出结果,并结束本次算法,继续求解其他可能的解的情况。 若v! =end_vex,则依次选择v的所有不在当前试探路径中邻接点s[v0].next往下搜索,这包括以下的操作: 试探: 通过A[top++]=p->adjvex将s[v0].next放在数组A中,并置visited[s[v0].next]为true,然后以s[v0].nex为起点往下搜索,直到搜索到终点{440}或者不满足循环条件为止 恢复: 通过A[--top]将s[v0].next恢复为不在当前的路径中,并置visited[v0]=false以使其在试探其他路径时可用。 每求出一种解就调用prtf()函数,进行输出。 输出过程如下: 路径存储在数组A中,A中存储的是路径中的各顶点,通过循环for(i=0;i 通过for(k=0;k printf("%d",s[j].vexdata[k]); 来输出该状态,当把数组A中的路径输出完以后就得到了一种解。 在dfs()函数中每求出一种解就调用一次prtf()函数,当遍历结束后,所有解也已全部求出并输出。 程序完成。 四、上机调试 1、语法错误机修改: 算法中定义了很多全局变量,在完成本程序的过程中,有些全局变量忘了赋值,这样系统就赋给它一个随机值,影响程序的正确性,发现错误后及时给它赋值,例如,作为数组下标的top,刚一个开始没有赋值,在输出路径是,全部都是随机数,在定义是令top=0即可。 语法的主要问题在于子函数定义,括号的配对,尤其是括号的配对,在有些地方使用的循环比较多,这样就会产生括号配对的错误,细心的检查,改错就行了。 还有一些输入错误,相应的将其解决。 2、逻辑问题修改及调整: 在jisuan函数中,通过两条for语句来控制酒杯的下标和比较,for(i=0;i break;} 这样调用一次save()函数就会执行下面的语句 if(i>sta)exdata[j]=part[j]; s[sta].next=NULL; if(! compare(part,end)) end_vex=sta; exdata)) break;exdata[j]=part[j]; s[sta].next=NULL; if(! compare(part,end)) end_vex=sta;ext; s[number].next=p;exdata[i]);ext=NULL; while(number<=sta) { for(i=0;i part[i]=s[number].vexdata[i];exdata[k]);ext; visited[v0]=true;exdata[k]); printf("\t"); } printf("\n共得到如下解法: \n"); findpath();//输出得到的解 } 八、参考书目 [1]、王昆仑,李红.数据结构与算法.北京: 铁道工业出版社,2007年6月
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 问题 数据结构 算法 课程设计 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)