第一篇:赌徒问题实验报告
赌徒问题实验报告
一、引言
赌徒问题是针对第四章动态规划的练习,同时也是对第三章介绍的贝尔曼方程和强化学习的基本知识的实际应用。两者紧密结合只有充分了解相关内容才能了解实验经过,才能对强化学习的基本问题有所了解。
二、相关知识介绍
1、马尔科夫性:能够保存此状态的来历的方式,称此方式是马尔科夫的。
也就是s',r,和历史的st,at,rt,st1,at1,...,r1,s0,a0来说,st1s',rt1r|st,at,rt,st1,at1,...r1,s0,a0}=Pr{st1s',rt1r|st,at}
Pr{在这种情况下,环境和任务是一体的,也都称为具有马尔可夫性质。
PS:每个状态都是有前一个可能的状态动作对和发生的各个概率计算得来的。
2、值函数:一个策略是每个状态sS以及动作aA(s)到状态s下采取动作a的概率(s,a)的一个映射。通俗地说,在策略下状态s的值记为V(s),它是从状态s开始并遵循策略的期望回报。对MDP而言,我们可以形式化地定义V(s)为:
kV(s)E{Rt|sts}Ertk1|sts,(3.8)
k0其中E{}表示了agent在遵循策略之后的期望值。而终止状态的值总是0。我们把函数V称为策略的状态值函数(state-value function for policy π)。
类似地,我们定义在策略下状态s中采取动作a的值,记为Q(s,a),作为在策略从状态s开始,采取动作a的期望回报:
kQ(s,a)E{Rt|sts,ata}Ertk1|sts,ata
(3.9)
k0我们将Q称为策略的动作值函数(action-value function for policy π)。
在强化学习和动态规划中,值函数的基本性质是它们满足一定的递归关系。对任意策略和状态s,在s的值和它可能的后继状态值之间,(3.10)的一致条件成立:
V(s)E{Rt|sts} k
Ertk1|sts
k0
Ert1k0rtk2|sts
k
(s,a)as'as'ak PRss'Ertk2|st1s',(3.10)
k0ass'ass'ass'(s,a)PRV(s')
其中,动作a是从集合A(s)中得到的,下一状态s'从集合S中得到的,或者是从情节式任务中的S中得到的。等式(3.10)是V的Bellman方程。它表达了一个状态的值和它的后继状态值之间的关系。
公式(3.10)就是贝尔曼方程,而V值就是贝尔曼方程的唯一解。
3、计算值函数:利用动态规划去计算值函数。找到符合Bellman最优方程
的最优值函数V*或Q*,从而得到最优策略。对于所有sS,aA(s),且s'S,Bellman最优方程如下:
V(s)maxE{rt1V(st1)|sts,ata}
a**
maxas'Pss'[Rss'V(s')]
(4.1)
aa*或
Q(s,a)E{rt1maxQ(st1,a')|sts,ata}
a'**
Ps'ass'[Rss'maxQ(s',a')]
a'a*(4.2)
PS:此方法就是修改贝尔曼方程从而得到V值的近似解。
三、实验过程简介
赌徒问题是一个典型的值迭代问题,值迭代是策略迭代的方法之一。
将贝尔曼最优方程转换成更新规则就可以得到值迭代。除了策略迭备份需要从所有的动作中选出最大动作以外,值迭代更新等同于策略评估更新。当每次扫描过后V的改动很小的时候就可以停止算法。认为V值已经解出。
以下是题目:
一个赌徒利用硬币投掷的反正面结果来赌博。假如投掷结果是硬币的正面朝上,那么他就赢得他所压的赌注,如果是反面朝上,那么他输掉他的赌注。当这个赌徒赢满100美元或者他输掉他所有的钱时,赌博结束。每一轮投掷,赌徒必须取出他资金的一部分作为赌注,赌注金额必须是整数。这个问题可以表述为一个无折扣的、情节式的有穷马尔可夫决策过程。状态就是赌徒所拥有的资金,s{1,2,,99},动作就是下赌注,a{1,2,,min(s,100s)}。除了赌徒达到100美元的目标而奖赏为+1以外,其他奖赏均为0。状态-值函数给出每个状态能够获胜的概率。策略就是如何决定每轮取出多少钱去下注。最优策略就是使取得最后胜利的概率最大化。令p代表硬币正面朝上的概率。假如p已知,那么整个问题也就知道了,并且可以得解,比如通过值迭代求解。图4.6就是当p0.4时,值迭代每一轮后值函数的变化情况和得到的最终策略。
以下是算法:
任意初始化V,比如:V(s)0,对于所有sS
Repeat 0
For each sS
vV(s)V(s)maxas'Pss'[Rss'V(s')]aa
max(,|vV(s)|)Until (一个极小的正数)
输出一个确定的策略 (s)argmaxas'Pss'[Rss'V(s')]
aa根据算法和题目的具体要求得到的C++代码如下:
#include
using namespace std;//vector
//将V值放在数组中存放,为了方便起见这里V[0]是不使用的!double AF(double S);
//a值的计算函数题目中a是a{1,2,,min(s,100s)} double Q(int S,int a);
//Q(S,a)动作值函数的计算
double RP(double S,double a);//这里P是加法的缩写M是减法的缩写赌徒赌钱可能的情况 double RM(double S,double a);// 为赢钱和输钱两种,+为赢概率0.4,同样输钱为-概率0.6; //=============================== void main(){
for(int i=0;i<100;i++)
//初始化V值为0; { V[i]=0;} double Delta=0.0;
//初始化△=0 double Cta=0.0000000001;
//初始化=0 double i;double K=0;do { for(int S=1;S<=99;S++)
//对于1~99个状态
{
} double v=V[S];
//将V值暂时保存下来
i=AF(S);
//i用来接收计算出来的a值 for(int a=0;a<=i;a++){ K+=Q(S,a);
//贝尔曼最优方程 } V[S]=K;Delta=max(Delta,fabs(v-V[S]));
//计算△
} while(Delta //当V的变化一定小的时候结束 for(int i=1;i<=99;i++) //输出最终的V值也就是贝尔曼方程的cout<<“V[”< //最优解,赌徒问题的最优解。double AF(double S){ } double T;T=min(S,100-S);return T; double Q(int S,int a){ double RESULT;RESULT=0.4*(RP(S,a)+V[S+a])+0.6*(RM(S,a)+V[S-a]);return RESULT;} //RP,RM判断汇报的值是1还是0.double RP(double S,double a){ } double C=S+a;if(C>=100)return 1.0;else return 0; double RM(double S,double a){ } double C=S-a;if(C>=100)return 1.0;else return 0;结果显示: 就一个50是对的,我就无语了。。。 V(s)maxas'Pss'[Rss'V(s')]aa 其实这个程序就是实现这个公式,我晕啊检查了几遍 maxas'还没发现问题,还麻烦老师帮忙看看。我知道这样不好,但是真的没招了,感觉这里可能有问题。。。 总结: 通过实验让我更加理解贝尔曼方程,对值函数的计算有了进一步的认识。同时学会了用值迭代的方法求出贝尔曼方程的最优解,对V与Q的关系理解更加深刻。V[S]=S状态下对应不同动作a的所有Q的和。 尊敬的 : 觉与老婆离婚并自愿放弃一切夫妻共同财产,净身出户。 2、我保证以后全心全意为这个家庭。用心去呵护家庭!不再 使家庭里再次发生不和谐的声音。凡是多和家里人商量,尽可能听取他们的意见和建议! 3、我保证以后尽心尽力为家庭付出。勤俭节约,勤劳朴素,保证人: 保证人:某某某 2015年5月17日 尊敬的领导,此致敬礼! 员工xx 尊敬的领导你好 己的行为感到了深深的内疚和不安,在此,我谨向领导做出了深刻的检讨。 通过这件事,我感到这虽然是一件偶然发生的事,但同时,也是我对自己工作的放松,带来的结果,经反思我觉得自己在工作责任心上仍旧非常欠缺,更为重要的是我感到对不起领导对我的信任,愧对领导的关心,这次的事使我不仅感到是自己耻辱。总之我的行为给公司带来了不好的影响,做出了这样的行为,我的心情非常沉重和羞愧。 我 对于这一切我还将进一步深入总结,深刻反省,恳请领导相信我能够记取教训、改正错误!敬的xx老师: 1 这样有事没请假,让老师担心我的安全。本应按时出现的我未能按时出现,试问怎么不会让平时十分关心爱护每一个学生的老师担心。而这样的担心很可能让老师整天工作分心,造成更为严重的后果。2 在同学们中间造成了不良的影响。由于我一个人的旷课,有可能造成别的同学的效仿,影响班级纪律性,也是对别的同学的父母的不负责。3影响个人综合水平的提高,使自身在本能提高的条件下未能得到提高 如今,错以铸成,我深感懊悔,深刻检讨自己的错误。 以上承诺我将自觉遵守,如有违反我将自愿接受依法依规最严厉的处罚。禁赌承诺书 七、如有违反,本人愿接受有关法律法规和相关规定的惩治。 十、本承诺书自签定之日起生效。xx-x力局 承诺人: 年月日 二、积极弘扬健康向上的文明娱乐风尚,不参与任何以营利为目的的打麻将、打扑克牌、下棋等活动。 七、如有违反承诺,一经查实,本人自愿接受任何处理。 八、本承诺书自签订之日起生效。 承诺人: 2016年3月10日篇四:2016戒赌保证书样本 2016戒赌保证书样本 戒赌保证书样本 本人xx。为了挽救这个原本幸福的家,本人保证做到以下几点: 一、工资卡交老婆保管 三、如若发现我再有复赌行为,本人将放弃财产继承权。 四、保证今后事事听众妻子,不在家中借酒行凶。xx,对不起,我错了,我以后再也不赌了,请你再给我一次机会,我们的儿子这么可爱,我不想儿子才三岁就没了妈妈,请你再给我一次机会,今后我一定努力工作,好好照顾你和儿子。 保证人: 日期: 戒赌保证书 尊敬的各位领导: 经过这次事件,我已经深深认识到了我的错误,感觉各位领导能让我悬崖勒马,给我改过自新的机会,我向各位如师如父的领导表示最崇高的敬意(n鞠躬)! 保证人: 日期:篇五:大家常说的职业赌徒的秘诀 大家常说的职业赌徒的秘诀 我是天天在赌场超过10个小时的赌客,别误会我并不是10小时都在赌,只是有时看别人赌,有时我半个小时就完成上午的任务(就是赢够数,我就看别人赌,什么样的赌法都有,但是大胆的说没有一个可以长期赢钱,没有一个方法可以长期(请注意是长期!)使用在某个一倍一的赌游戏之中,更别说是机会少于50%的高赔率赌戏了。 你问我有没有更好的方法对付赌场,哈哈,赌场是我的衣食父母,我们不应该想对付它,应该和它做朋友! 永远只赌一倍一的游戏,记住下面三个诀窍! 1、下注方法 2、注码法 3、时间观念 1+2+3=赢 1、下注方法 例如赌大小,你根据什么去下注,下一把是买大还是买小。先定下下注方案,比如是只赌4把,4把内赢一把就行,只赌大,大,小,小,这条路,看见前面开出小,小,大,可以开始下注,为什么?因为前面3口你要是下注已经输了3把,现在开始下注你已经在心理上占优势。大,大,小,小。赢一把就停。4把不中也停。方案你自己定,定下来就执行,就这么简单,不要管开出几点,只管大小,不要让其它的因素影响你下一把的投注方向,遇围骰算输,即停不追。 2、注码法 因为赌场的所有赌戏都是对赌客不利(百家乐只买闲除外)。平注法无法保证长期在赌场赢利,只有适当加注才能战胜赌场设下的不公平游戏规则。在这里我只能说 1、3、7、15和1、2、4、8,这种强攻自杀式的注码法还是少用为妙(除非特别原因),我只提供3种稳中求胜的注码法供你参考1、2、3或者1、1、3、5和1、1、3、6,这3种都是稳中求胜的。两赢一平或者2赢2平或者三赢一平,所用注码最多11注,哪怕断缆以后也容易追回来,切记切记! 3、时间观念 以上是本人在赌场这几年来的一些心得,只希望能帮到一些经常赌运不佳的朋友。 世界其实就是一个赌场,人生其实就是一个赌局,我们其实就是一群赌徒。 当我们懵懂无知踏进赌场时,就应该知道:我们出去之后不可能再是进来时那般天真无邪;当我们跃跃欲试接触赌局时,就应该知道:我们只有两种结果,要么满载而归,要么倾家荡产。当我们掩饰内心靠近赌徒时,就应该知道:时间会磨平我们的棱角,不动声色的为我们戴上我们当初最不愿意戴上如今最不愿意卸下的面具。 如果我们完完全全的把人生当成一个赌局,真的可以省心省力,真的能够受益匪浅,真的足以一身轻松。 赌徒只有两种想法:赌这个赢、赌那个赢。其实就像我们面临的选择一样:选这个好、选那个好。都是同一个道理,但是为什么有些人倾家荡产,有些人却满载而归呢? 赌场里虽然有很多人,但是大致可以分为两种,第一种:“坚信自己的选择,赌这个,输光了我也认了。”第二种:“我要赌这个吗?万一输了呢?不行,我再想想,呀!真的是这个,早知道我就下注了,真后悔!”这就是倾家荡产或满载而归的原因。 两种赌徒的话简单的把我们的性格反映出来,生活中不也是这样么?机会就在眼前,有些人把握时机不断努力然后享受胜利最后满载而归,有些人看着时机再三斟酌然后懦弱放弃最后倾家荡产。 看到这里,有些人可能会有不理解,我们为人处世处处要小心谨慎,方才的故事中第二种赌徒只是谨慎了些,似乎没有什么大错?是的,为人处世需要小心谨慎我不反对,但是这里又要关系到对于谨慎的理解。 谨慎,是指已经思考的面面俱到甚至已经考虑到了事情最严重的后果然后行事,这时候我们再倒回第二种赌徒的话中去看看,与其说他小心谨慎,倒不如说他惧怕失败更贴切些吧?是,我也怕输,我们都怕输,但是正是因为如此,我们才会重视,不是么?人生亦是如此,很多时候怕选择错了于是不敢选,于是错过,于是将错就错,但是我们想想,回想起人生中我们的那些赌局,会不会很美好?会的,因为我们曾经追求过,我们曾经在追求中享受过快乐,所以这些回忆也是美好的。 真正的赌徒,会考虑到事情的方方面面,做不让自己后悔的事情。真正的赌徒,即便输了,也会从中寻乐,因为有遗憾才会回忆,够遗憾才会铭记。 真正的赌徒,如果在做出选择时听信了别人的话,然后输了,他们不会后悔,因为那是他们选择相信的。 真正的赌徒,如果在做出选择时听信了自己的心,然后输了,他们不会后悔,因为那是他们选择坚定的。 人生赌局,与其顾虑太多,不如放手一搏。哪怕输了,日后回想起来,我们还是会享受那段追求成功的时光。 一、实验名称: 用贪心算法解决汽车加油次数最少问题。 二、实验目的: 一辆汽车加满油后,可行使n千米。旅途中有若干个加油站。若要使沿途加油次数最少,设计一个有效算法,对于给定的n和k个加油站位置,指出应在哪些加油站停靠加油才能使加油次数最少。输入数据中,第一行有2个正整数,分别表示汽车加满油后可行驶n千米,且旅途中有k个加油站。接下来的1行中,有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。第0个加油站表示出发地,汽车已加满油。第k+1个加油站表示目的地。输出为最少的加油次数,如果无法到达目的地,则输出“No Solution”。 实验提示: 把两加油站的距离放在数组中,a[1..k]表示从起始位置开始跑,经过k个加油站,a[i]表示第i-1个加油站到第i个加油站的距离。汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。 输入数据示例 7 7 1 2 3 4 5 1 6 6 输出数据 4。 三、使用的策略: 贪心算法、回溯算法等。 四、实验内容: (一)问题描述 一辆汽车加满油后可以行驶N千米。旅途中有若干个加油站。指出若要使沿途的加油次数最少,设计一个有效的算法,指出应在那些加油站停靠加油。 给出N,并以数组的形式给出加油站的个数及相邻距离,指出若要使沿途的加油次数最少,设计一个有效的算法,指出应在那些加油站停靠加油。要求:算法执行的速度越快越好。 (二)问题分析(前提行驶前车里加满油)对于这个问题我们有以下几种情况:设加油次数为k,每个加油站间距离为a[i];i=0,1,2,3„„n 1.始点到终点的距离小于N,则加油次数k=0; 2.始点到终点的距离大于N,A 加油站间的距离相等,即a[i]=a[j]=L=N,则加油次数最少k=n; B 加油站间的距离相等,即a[i]=a[j]=L>N,则不可能到达终点; C 加油站间的距离相等,即a[i]=a[j]=L D 加油站间的距离不相等,即a[i]!=a[j],则加油次数k通过以下算法求解。 (三)算法描述 1.贪心算法解决方案 贪心算法的基本思想 该题目求加油最少次数,即求最优解的问题,可分成几个步骤,一般来说,每个步骤的最优解不一定是整个问题的最优解,然而对于有些问题,局部贪心可以得到全局的最优解。贪心算法将问题的求解过程看作是一系列选择,从问题的某一个初始解出发,向给定目标推进。推进的每一阶段不是依据某一个固定的递推式,而是在每一个阶段都看上去是一个最优的决策(在一定的标准下)。不断地将问题实例归纳为更小的相似的子问题,并期望做出的局部最优的选择产生一个全局得最优解。 贪心算法的适用的问题 贪心算法适用的问题必须满足两个属性: (1)贪心性质:整体的最优解可通过一系列局部最优解达到,并且每次的选择可以依赖以前做出的选择,但不能依赖于以后的选择。 (2)最优子结构:问题的整体最优解包含着它的子问题的最优解。 贪心算法的基本步骤 (1)分解:将原问题分解为若干相互独立的阶段。(2)解决:对于每一个阶段求局部的最优解。(3)合并:将各个阶段的解合并为原问题的解。[问题分析] 由于汽车是由始向终点方向开的,我们最大的麻烦就是不知道在哪个加油站加油可以使我们既可以到达终点又可以使我们加油次数最少。 提出问题是解决的开始.为了着手解决遇到的困难,取得最优方案。我们可以假设不到万不得已我们不加油,即除非我们油箱里的油不足以开到下一个加油站,我们才加一次油。在局部找到一个最优的解。却每加一次油我们可以看作是一个新的起点,用相同的递归方法进行下去。最终将各个阶段的最优解合并为原问题的解得到我们原问题的求解。 加油站贪心算法设计(C): include int add(int b[ ],int m,int n){ //求一个从m到n的数列的和 int sb;for(int i=m;i int Tanxin(int a[n], int N)//a[n]表示加油站的个数,N为加满油能行驶的最远距离 { int b[n];//若在a[i]加油站加油,则b[i]为1,否则为0 int m=0; if(a[i]>N)return ERROR;//如果某相邻的两个加油站间的距离大于N,则不能到达终点 if(add(a[i], 0, n) { //如果这段距离小于N,则不需要加油 b[i]=0; return add(b[i],0,n); } if(a[i]==a[j]&&a[i]==N) { //如果每相邻的两个加油站间的距离都是N,则每个加油站都需要加油 b[i]=1; return add(b[i],0,n); } if(a[i]==a[j]&&a[i] { //如果每相邻的两个加油站间的距离相等且都小于N if(add(a[i],m,k)< N && add(a[i],m,k+1)> N) { b[k]=1; m+=k; } return add(b[i],0,n); } if(a[i]!=a[j]) { //如果每相邻的两个加油站间的距离不相等且都小于N if(add(a[i],m,k)< N && add(a[i],m,k+1)> N) { b[k]=1; m+=k; } return add(b[i],0,n); } viod main(){ int a[ ]; scanf(“%d”,a); scanf(“/n”); scanf(“/d”,&N); Tanxin(a[ ],0,n);} 贪心算法正确性证明: 贪心选择性质 所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。对于一个具体的问题,要确定它是否具有贪心性质,我们必须证明每一步所作的贪心选择最终导致问题的一个整体最优解。该题设在加满油后可行驶的N千米这段路程上任取两个加油站A、B,且A距离始点比B距离始点近,则若在B加油不能到达终点那么在A加油一定不能到达终点,如图: 由图知:因为m+N 当一个问题大的最优解包含着它的子问题的最优解时,称该问题具有最优子结构性质。由于(b[1],b[2],„„b[n])是这段路程加油次数最少的一个满足贪心选择性质的最优解,则易知若在第一个加油站加油时,b[1]=1,则(b[2],b[3],„„b[n])是从 a[2]到a[n]这段路程上加油次数最少且这段路程上的加油站个数为(a[2],a[3],„„a[n])的最优解,即每次汽车中剩下的油不能在行驶到下一个加油站时我们才在这个加油站加一次油,每个过程从加油开始行驶到再次加油满足贪心且每一次加油后相当于与起点具有相同的条件,每个过程都是相同且独立,也就是说加油次数最少具有最优子结构性质。贪心算法时间复杂度分析 由于若想知道该在哪个加油站加油就必须遍历所有的加油站,且不需要重复遍历,所以时间复杂度为O(n)。 五、实验心得: 在贪心算法中,每次做出的选择仅在当前的状态下做出的最好的选择,即局部最优选择。然后再去解做出这个选择后产生的相应的子问题。不是每个问题用贪心算法都可以一定得到最优解,除非该问题具有贪心选择性质(所求问题的整体最优解可以通过一系列局部最优的选择而得到)和最优子结构性质。 通过实验对贪心算法和回溯算法以及动态规划算法有了更深一步的理解,知道了它们适合解决哪类的问题,锻炼和提高了我们分析问题解决问题的能力,同时让我们更体会到团结一致协作的重要性。 《数据结构与算法设计》 迷宫问题实验报告 ——实验二 专业:物联网工程 班级:物联网1班 学号:15180118 姓名:刘沛航 一、实验目的 本程序是利用非递归的方法求出一条走出迷宫的路径,并将路径输出。首先由用户输入一组二维数组来组成迷宫,确认后程序自动运行,当迷宫有完整路径可以通过时,以0和1所组成的迷宫形式输出,标记所走过的路径结束程序;当迷宫无路径时,提示输入错误结束程序。 二、实验内容 用一个m*m长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序对于任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。 三、程序设计 1、概要设计 (1)设定栈的抽象数据类型定义 ADT Stack{ 数据对象:D={ai|ai属于CharSet,i=1、2…n,n>=0} 数据关系:R={ 操作结果:构造一个空栈 Push(&S,e) 初始条件:栈已经存在 操作结果:将e所指向的数据加入到栈s中 Pop(&S,&e) 初始条件:栈已经存在 操作结果:若栈不为空,用e返回栈顶元素,并删除栈顶元素 Getpop(&S,&e) 初始条件:栈已经存在 操作结果:若栈不为空,用e返回栈顶元 StackEmpty(&S) 初始条件:栈已经存在 操作结果:判断栈是否为空。若栈为空,返回1,否则返回0 Destroy(&S) 初始条件:栈已经存在 操作结果:销毁栈s }ADT Stack (2)设定迷宫的抽象数据类型定义 ADT yanshu{ 数据对象:D={ai,j|ai,j属于{‘ ’、‘*’、‘@’、‘#’},0<=i<=M,0<=j<=N} 数据关系:R={ROW,COL} ROW={ InitMaze(MazeType &maze, int a[][COL], int row, int col){ 初始条件:二维数组int a[][COL],已经存在,其中第1至第m-1行,每行自第1到第n-1列的元素已经值,并以值0表示障碍,值1表示通路。 操作结果:构造迷宫的整形数组,以空白表示通路,字符‘0’表示障碍 在迷宫四周加上一圈障碍 MazePath(&maze){ 初始条件:迷宫maze已被赋值 操作结果:若迷宫maze中存在一条通路,则按如下规定改变maze的状态;以字符‘*’表示路径上的位置。字符‘@’表示‘死胡同’;否则迷宫的状态不变 } PrintMaze(M){ 初始条件:迷宫M已存在 操作结果:以字符形式输出迷宫 } }ADTmaze (3)本程序包括三个模块 a、主程序模块 void main(){ 初始化; 构造迷宫; 迷宫求解; 迷宫输出; } b、栈模块——实现栈的抽象数据类型 c、迷宫模块——实现迷宫的抽象数据类型 2、详细设计 (1)坐标位置类型: typedef struct{ int row;//迷宫中的行 int col;//......的列 }PosType;//坐标 (2)迷宫类型: typedef struct{ int m,n;int arr[RANGE][RANGE];}MazeType;//迷宫类型 void InitMaze(MazeType &maze, int a[][COL], int row, int col)//设置迷宫的初值,包括边缘一圈的值 Bool MazePath(MazeType &maze,PosType start, PosType end)//求解迷宫maze中,从入口start到出口end的一条路径 //若存在,则返回true,否则返回false Void PrintMaze(MazeType maze)//将迷宫打印出来 (3)栈类型: typedef struct{ int step;//当前位置在路径上的“序号” PosType seat;//当前的坐标位置 DirectiveType di;//往下一个坐标位置的方向 }SElemType;//栈的元素类型 typedef struct{ SElemType *base;SElemType *top;int stacksize;}SqStack;栈的基本操作设置如下: Void InitStack(SqStack & S) //初始化,设S为空栈(S.top=NUL)Void DestroyStack(Stack &S)//销毁栈S,并释放空间 Void ClearStack(SqStack & S)//将栈S清空 Int StackLength(SqStack &S)//返回栈S的长度 Status StackEmpty(SqStack &S)?、若S为空栈(S.top==NULL),则返回TRUE,否则返回FALSE Statue GetTop(SqStack &S,SElemType e) //r若栈S不空,则以e待会栈顶元素并返回TRUE,否则返回FALSE Statue Pop(SqStack&S,SElemType e)//若分配空间成功,则在S的栈顶插入新的栈顶元素s并返回TRUE //否则栈不变,并返回FALSE Statue Push(SqStack&S,SElemType &e)//若分配空间程控,则删除栈顶并以e带回其值,则返回TRUE //否则返回FALSE Void StackTraverse(SqStack &S,Status)(*Visit)(SElemType e))//从栈顶依次对S中的每个节点调用函数Visit 4求迷宫路径的伪码算法: Status MazePath(MazeType &maze,PosType start, PosType end){ //求解迷宫maze中,从入口start到出口end的一条路径 InitStack(s);PosType curpos = start;int curstep = 1;//探索第一部 do{ if(Pass(maze,curpos)){ //如果当前位置可以通过,即是未曾走到的通道块 FootPrint(maze,curpos);//留下足迹 e = CreateSElem(curstep,curpos,1);//创建元素 Push(s,e);if(PosEquare(curpos,end))return TRUE;curpos =NextPos(curpos,1);//获得下一节点:当前位置的东邻 curstep++;//探索下一步 }else{ //当前位置不能通过 if(!StackEmpty(s)){ Pop(s,e);while(e.di==4 &&!StackEmpty(s)){ MarkPrint(maze,e.seat);Pop(s,e);//留下不能通过的标记,并退回步 } if(e.di<4){ e.di++;Push(s,e);//换一个方向探索 curpos = NextPos(e.seat,e.di);//设定当前位置是该方向上的相块 }//if }//if }//else }while(!StackEmpty(s));return FALSE;} //MazePath 四、程序调试分析 1.首先呢,想自己读入数据的,回来发现那样,很麻烦,所以还是事先定义一个迷宫。 2.栈的元素类型 一开始有点迷惑,后来就解决了 3.本题中三个主要算法;InitMaze,MazePath和PrintMaze的时间复杂度均为O(m*n)本题的空间复杂度也是O(m*n) 五、用户使用说明 1.本程序运行在windows系列的操作系统下,执行文件为:Maze_Test.exe。 六、程序运行结果 1.建立迷宫: 2.通过1功能建立8*8的迷宫后,通过2功能继续建立迷宫内部: 通过建立自己设定单元数目建立迷宫内墙。3.通过3功能观察已建立的迷宫结构: 4.通过4功能确立迷宫起点和终点: (此处像我们随机选择4,4和2,7分别为起点终点) 5.执行5功能,判断是否有路径走出迷宫: 这种情况无法走出迷宫。 我们再次观察图像设4,4和1,6分别为起点终点,再运行5功能。 观察到可以成功解开迷宫步数从1依次开始。 七、程序清单 #include // 列值 #define MAXLENGTH 25 // 设迷宫的最大行列为25 typedef int MazeType[MAXLENGTH][MAXLENGTH];// 迷宫数组[行][列] typedef struct // 栈的元素类型 { int ord;// 通道块在路径上的"序号" PosType seat;// 通道块在迷宫中的"坐标位置" int di;// 从此通道块走向下一通道块的"方向"(0~3表示东~北)}SElemType; // 全局变量 MazeType m;// 迷宫数组 int curstep=1;// 当前足迹,初值为1 #define STACK_INIT_SIZE 10 // 存储空间初始分配量 #define STACKINCREMENT 2 // 存储空间分配增量 // 栈的顺序存储表示 typedef struct SqStack { SElemType *base;// 在栈构造之前和销毁之后,base的值为NULL SElemType *top; int stacksize; // 构造一个空栈S int InitStack(SqStack *S){ // 为栈底分配一个指定大小的存储空间 (*S).base =(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if(!(*S).base) (*S).top =(*S).base; return 1; // 栈底与栈顶相同表示一个空栈 (*S).stacksize = STACK_INIT_SIZE;exit(0);}SqStack;// 顺序栈 // 栈顶指针 // 当前已分配的存储空间,以元素为单位 } // 若栈S为空栈(栈顶与栈底相同的),则返回1,否则返回0。int StackEmpty(SqStack S){ if(S.top == S.base) else } // 插入元素e为新的栈顶元素。int Push(SqStack *S, SElemType e){ if((*S).top-(*S).base >=(*S).stacksize)// 栈满,追加存储空间 { } *((*S).top)++=e;return 1;} // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回1;否则返回0。int Pop(SqStack *S,SElemType *e){ if((*S).top ==(*S).base) 左 return 1;} // 定义墙元素值为0,可通过路径为1,不能通过路径为-1,通过路径为足迹 // 当迷宫m的b点的序号为1(可通过路径),return 1;否则,return 0。int Pass(PosType b){ if(m[b.x][b.y]==1) else return 0;return 1;return 0;*e = *--(*S).top; // 这个等式的++ * 优先级相同,但是它们的运算方式,是自右向 (*S).base =(SElemType *)realloc((*S).base ,(*S).top =(*S).base+(*S).stacksize;(*S).stacksize += STACKINCREMENT;((*S).stacksize + STACKINCREMENT)* sizeof(SElemType));exit(0);if(!(*S).base)return 0;return 1;} void FootPrint(PosType a) // 使迷宫m的a点的序号变为足迹(curstep),表示经过 { m[a.x][a.y]=curstep;} // 根据当前位置及移动方向,返回下一位置 PosType NextPos(PosType c,int di){ PosType direc[4]={{0,1},{1,0},{0,-1},{-1,0}};// {行增量,列增量} // 移动方向,依次为东南西北 c.x+=direc[di].x;c.y+=direc[di].y;return c;} // 使迷宫m的b点的序号变为-1(不能通过的路径)void MarkPrint(PosType b){ m[b.x][b.y]=-1;} // 若迷宫maze中存在从入口start到出口end的通道,则求得一条 // 存放在栈中(从栈底到栈顶),并返回1;否则返回0 int MazePath(PosType start,PosType end){ SqStack S;PosType curpos;SElemType e; InitStack(&S);curpos=start;do { if(Pass(curpos)){// 当前位置可以通过,即是未曾走到过的通道块 FootPrint(curpos);// 留下足迹 e.ord=curstep;e.seat.x=curpos.x;e.seat.y=curpos.y;e.di=0;Push(&S,e);// 入栈当前位置及状态 curstep++;// 足迹加1 if(curpos.x==end.x&&curpos.y==end.y)// 到达终点(出口) } else return 1;curpos=NextPos(curpos,e.di);{// 当前位置不能通过 } if(!StackEmpty(S)){ } Pop(&S,&e);// 退栈到前一位置 curstep--;while(e.di==3&&!StackEmpty(S))// 前一位置处于最后一个方向(北){ } if(e.di<3)// 没到最后一个方向(北){ } e.di++;// 换下一个方向探索 Push(&S,e);curstep++;// 设定当前位置是该新方向上的相邻块 curpos=NextPos(e.seat,e.di); MarkPrint(e.seat);// 留下不能通过的标记(-1)Pop(&S,&e);// 退回一步 curstep--;}while(!StackEmpty(S));return 0;} // 输出迷宫的结构 void Print(int x,int y){ int i,j; for(i=0;i } } void main(){ PosType begin,end;int i,j,x,y,x1,y1,n,k;for(j=0;j //清屏函数 printf(“***************************************************nnn”);printf(“ 1请输入迷宫的行数,列数n”);printf(“ 2请输入迷宫内墙单元数n”);printf(“ 3迷宫结构如下n”);printf(“ 4输入迷宫的起点和终点n”);printf(“ 5输出结果n”);printf(“ 0退出n”);printf(“nn请选择 ”);scanf(“%d”,&n);switch(n){ case 1:{ printf(“请输入迷宫的行数,列数(包括外墙):(空格隔开)”); scanf(“%d%d”, &x, &y); for(j=1;j { for(i=1;i for(j=1;j // 迷宫左边列的周边即左边墙 m[j][y-1]=0;// 迷宫右边列的周边即右边墙 for(i=0;i // 迷宫上面行的周边即上边墙 m[x-1][i]=0;// 迷宫下面行的周边即下边墙 物 联 网 班 -15180118-刘沛 航 } }break; case 2: {printf(“请输入迷宫内墙单元数:”); scanf(“%d”,&j); printf(“请依次输入迷宫内墙每个单元的行数,列数:(空格隔开)n”); for(i=1;i<=j;i++) { scanf(“%d%d”,&x1,&y1); } m[x1][y1]=0; }break; case 3:{ Print(x,y);printf(“刘沛航建立的迷宫,定义墙元素值为0,可通过路径为1,输入0退出”);scanf(“%d”,&k);}break; case 4:{ printf(“请输入起点的行数,列数:(空格隔开)”); scanf(“%d%d”,&begin.x,&begin.y); printf(“请输入终点的行数,列数:(空格隔开)”); scanf(“%d%d”,&end.x,&end.y);}break; case 5:{ if(MazePath(begin,end))// 求得一条通路 { } else printf(“此迷宫没有从入口到出口的路径,谢谢使用刘沛航的程序n”);printf(“输入0退出”);scanf(“%d”,&k);}break;} }while(n!=0);} printf(“此迷宫从入口到出口的一条路径如下,谢谢使用刘沛航的程序:n”);Print(x,y);// 输出此通路 文档为doc格式 人工智能——四皇后问题 一、问题描述 四皇后问题 一个4×4国际象棋盘,依次放入四个皇后,条件:每行、每列及对角线上只允许出现一枚棋子。 设:DATA=L(表) x∈L x ∈﹛i j﹜ 1≤ i, j...... 材料力学实验报告问题分析
1、 为何在拉伸试验中必须采用标准试件或比例试件,材料相同而长短不同的试件延伸率是否相同? 答:拉伸实验中延伸率的大小与材料有关,同时与试件的...... 1.上机内容 传教士与野人问题求解(宽度搜索算法)二 二 问题背景:从前有一条河,河的左岸有 m 个传教士(Missionary)和 m 个野人(Cannibal),和一艘最多可乘 n 人的小船。约定左岸,右...... 实 验 二 经 典 的 生 产 者 — 消 费 者 问 题一、目的实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。二、实验内容及要求编制生产者—消费者算法...... 实验报告五 ——生产者和消费者问题 姓名:丛菲 学号:20100830205 班级:信息安全二班 一、实习内容 • • 1、模拟操作系统中进程同步和互斥 2、实现生产者和消费者问题的算法实...... 人工智能实验报告实验六遗传算法实验II一、实验目的:熟悉和掌握遗传算法的原理、流程和编码策略,并利用遗传求解函数优化问题,理解求解TSP问题的流程并测试主要参数对结果的影...... 《体育测量与评价》实验报告模板
课程名称:体育测量与评价
实验名称:ISAK全套人体测量指标(共39项)测试
一、预习报告
1.实验目的
①通过实验强化体格及身体成分测量的有关知...... 西华大学学生上机实践报告
西华大学上机实践报告课程名称:网络程序设计方法
指导教师:陈克力
上机实践名称:根据实验指导书填写实验名称
上机实践编号:填写第几个实验(如实验1)
年......第二篇:赌徒的保证书
第三篇:赌徒情感散文
第四篇:汽车加油问题实验报告
第五篇:数据结构迷宫问题实验报告
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。 四皇后问题实验报告
材料力学实验报告问题分析
传教士和野人问题实验报告(大全五篇)
操作系统实验报告经典生产者—消费者问题范文大全
实验报告五 生产者和消费者问题
遗传算法求解TSP问题实验报告
实验报告
实验报告