




已阅读5页,还剩5页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
算法与程序实践习 题 解 答5模拟现实中的有些问题,难以找到公式或规律来解决,只能按照一定步骤,不停地做下去,最后才能得到答案。这样的问题,用计算机来解决十分合适,只要能让计算机模拟人在解决此问题的行为即可。这一类的问题可以称之为“模拟题”。比如下面经典的约瑟夫问题:CS51:约瑟夫问题(来源: 2746,程序设计导引及在线实践(李文新)例6.1 P141)问题描述:约瑟夫问题:有只猴子,按顺时针方向围成一圈选大王(编号从到),从第号开始报数,一直数到,数到的猴子退出圈外,剩下的猴子再接着从1 开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入,后,输出最后猴王的编号。输入:每行是用空格分开的两个整数,第一个是 n,第二个是m ( 0 m, n 300) 。最后一行是:0 0输出:对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号。样例输入:6 212 48 30 0样例输出:517解题思路:初一看,很可能想把这道题目当作数学题来做,即认为结果也许会是以n和m为自变量的某个函数f(n,m),只要发现这个函数,问题就迎刃而解。实际上,这样的函数很难找,甚至也许根本就不存在。用人工解决的办法就是将n个数写在纸上排成一圈,然后从1开始数,每数到第m个就划掉一个数,一遍遍做下去,直到剩下最后一个。有了计算机,这项工作做起来就会快多了,我们只要编写一个程序,模拟人工操作的过程就可以了。用数组anLoop来存放n个数,相当于n个数排成的圈;用整型变量 nPtr指向当前数到的数组元素,相当于人的手指;划掉一个数的操作,就用将一个数组元素置0的方法来实现。人工数的时候,要跳过已经被划掉的数,那么程序执行的时候,就要跳过为0的数组元素。需要注意的是,当nPtr指向anLoop中最后一个元素(下标n-1)时,再数下一个,则nPtr要指回到数组的头一个元素(下标0),这样anLoop才象一个圈。参考程序:#include #include #define MAX_NUM 300int aLoopMAX_NUM+1;int main()int n,m,i;while(1)scanf(%d%d,&n,&m);if(n=0) break;for(i=0;in;i+)aLoopi=i+1;int nPtr=0; /存储位置信息for(i=0;in;i+) /每次循环将1只猴子赶出圈子int nCount=0; /记录本轮数到的猴子数目while(nCountm) /一直要数出m个猴子while(aLoopnPtr=0) /跳过已经出圈的猴子nPtr=(nPtr+1)%n; /到下一个位置,如果到最后就跳到第1个nCount+;nPtr=(nPtr+1)%n;nPtr-; /找到要出圈的猴子,位置要回退一个if(nPtr0)nPtr=n-1;if(i=n-1) /最后一个出圈的猴子printf(%dn,aLoopnPtr);aLoopnPtr=0;return 0;注意事项:上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0 的数组元素,因此算法的效率不是很高。后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。n 个元素的数组,从下标0 的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+ 1 )% n”。这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。对于本题,虽然很难直接找出结果函数 f(n, m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放 n 个数。请写出这个高效而节省空间的程序。问题一:在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。比如,语句15,循环是从0到n-1,而不是从0 到n。问题二:nPtr-到nPtr=n-1回退一个位置,易被忽略或写错。比如只写了语句nPtr-,忘了处理nPtr变成小于0的情况。CS52:醉酒的狱卒(The Drunk Jailer)(来源:POJ 1218 ZOJ 1350,程序设计方法及在线实践指导(王衍等) P169)问题描述:某个监狱有一排、共n间牢房,一间挨一间。每间牢房关着一名囚犯,每间牢房的门刚开始时都是关着的。有一天晚上,狱卒厌烦了看守工作,决定玩一个游戏。游戏的第1轮,他喝了一杯酒,然后沿着监狱,把所有的牢房的门挨个挨个打开;第2轮,他又喝了一杯酒,然后沿着监狱,把编号为偶数的牢房的门关上;第3轮,他又喝了一杯酒,然后沿着监狱,对编号为3的倍数的牢房,如果牢房的门开着,则关上,否则打开;,狱卒重复游戏n轮。游戏结束后,他喝下最后一杯酒,醉倒了。这时,囚犯才意识到他们牢房的门可能是开着的,而且狱卒醉倒了,所以他们越狱了。给定牢房的数目,求越狱囚犯的人数。输入:输入文件的第1行为一个正整数,表示测试数据的个数。每个测试数据占一行,为一个整数n,5=n=100,表示牢房的数目。输出:对每个测试数据所表示的牢房数目n,输出越狱的囚犯人数。样例输入:25100样例输出:210解题分析:n轮游戏后,哪些牢房的门是开着的,并无规律可循。但这个游戏的规则和过程很简单:游戏有n轮,第j轮游戏是将编号为j的倍数的牢房状态变反,原来是开着的,则关上,原来是关着的,则打开,j=1,2,3,n。这些规则和过程用程序能较容易地实行,所以适合采用“模拟”的思路来求解。具体实现时可定义一个一维数组,每个元素表示对应牢房的状态,初始为1,表示牢房门是关着的,然后模拟游戏的每一轮:第j轮时,改变牢房编号为j的倍数的牢房状态,为0则改为1,为1则改为0。n轮游戏后,统计状态为0的牢房数即可。参考程序:#include #include int main()int nCases,n;int prision101; /n个牢房,n最多100个,1表示锁着,0表示开着int i,j;scanf(%d,&nCases);for(i=0;inCases;i+)scanf(%d,&n);for(j=1;j=n;j+)prisionj=1;for(j=1;j=n;j+)int tmp=j;while(tmp=n)prisiontmp=(prisiontmp=1)?0:1;tmp+=j;int num=0;for(j=1;j=n;j+)if(!prisionj) num+;printf(%dn,num);return 0;CS53:花生问题(同CS93)(来源: 2950,程序设计导引及在线实践(李文新)例4.3 P107)问题描述:鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!熊字”。鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图5-1)。有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”我们假定多多在每个单位时间内,可以做下列四件事情中的一件:1) 从路边跳到最靠近路边(即第一行)的某棵花生植株;2) 从一棵植株跳到前后左右与之相邻的另一棵植株;3) 采摘一棵植株下的花生;4) 从最靠近路边(即第一行)的某棵花生植株跳回路边。图 5-1 花生地图 5-2 摘花生过程现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。例如在图5-2所示的花生田里,只有位于(2, 5), (3, 7), (4, 2), (5, 4) 的植株下长有花生,个数分别为13、7、15、9。沿着图示的路线,多多在21个单位时间内,最多可以采到37个花生。输入:输入的第一行包括三个整数,M, N 和K,用空格隔开;表示花生田的大小为M *N(1 = M, N = 20),多多采花生的限定时间为K(0 = K = 1000 )个单位时间。接下来的M 行,每行包括N 个非负整数,也用空格隔开;第i + 1 行的第j 个整数Pij(0 = Pij = 500) 表示花生田里植株(i, j)下花生的数目,0 表示该植株下没有花生。输出:输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。样例输入:6 7 210 0 0 0 0 0 00 0 0 0 13 0 00 0 0 0 0 0 70 15 0 0 0 0 00 0 0 9 0 0 00 0 0 0 0 0 0样例输出:37解题思路:试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。结果只能是做了才知道。即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。参考程序:#include #include #include #include int T,M,N,K;#define MAX_NUM 55int aFieldMAX_NUMMAX_NUM;int main()int i,j,t,m,n;scanf(%d,&T);for(t=0;tT;t+)scanf(%d%d%d,&M,&N,&K);for(m=1;m=M;m+)for(n=1;n=N;n+)scanf(%d,&aFieldmn);int nTotalPeanuts=0; /摘得的花生总数int nTotalTime=0; /已经花去的总时间int nCuri=0,nCurj; /当前位置坐标while(nTotalTimeK)int nMax=0,nMaxi,nMaxj; /最大的花生数目,及其所处的位置/寻找下一个最大花生数目及其位置for(i=1;i=M;i+)for(j=1;j=N;j+)if(nMaxaFieldij)nMax=aFieldij;nMaxi=i;nMaxj=j;if(nMax=0) /地里没有花生了break;if(nCuri=0)nCurj=nMaxj; /如果当前位置在路上,那么应走到横坐标nMaxj处,再进入花生地/下面检查剩余的时间够不够走到nMaxi,nMaxj处,摘取花生,并回到路上if(nTotalTime+nMaxi+1+abs(nMaxi-nCuri)+abs(nMaxj-nCurj)=K)nTotalTime+=1+abs(nMaxi-nCuri)+abs(nMaxj-nCurj);nCuri=nMaxi;nCurj=nMaxj;nTotalPeanuts+=aFieldnMaxinMaxj;aFieldnMaxinMaxj=0; /摘走花生赋值为0elsebreak;printf(%dn,nTotalPeanuts);return 0;实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField00还是aField11 对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1 个单位时间,题目中的坐标又都是从1 开始,所以若aField11 对应花生地的左上角,则从aFieldij 点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C+ 的数组下标从0 开始,我们使用数组的时候,就要从下标为0 的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS54:分糖果的游戏(Candy Sharing Game)(来源:POJ 1666 ZOJ 1814,程序设计方法及在线实践指导(王衍等) P186)问题描述:N个学生围成一圈坐着,面向老师(老师位于中心)。每个学生手头上刚开始都有偶数块糖果。每轮游戏:老师一吹哨子,每个学生将他的糖果的一半分给他右边相邻的学生;N个学生分糖果完毕后,如果某个学生手头上的糖果数为奇数,则由老师再给一块糖果凑成偶数块。当所有学生的糖果数一样时,则游戏结束。要求编写程序,输出游戏进行的轮数,以及最终每个学生手头糖果的块数。输入:输入文件描述了多次游戏(即输入文件中包含多个测试数据)。每次游戏的数据第一行是一个整数N,表示学生的人数,接下来是N个偶数,代表初始时N个学生手上的糖果数目(逆时针排列)。输入文件最后一行为0,表示输入结束。输出:对每次游戏,输出游戏进行的轮数,以及游戏结束后每个学生手上的糖果数。样例输入:6362222211222018161412108642424680样例输出:15 1417 224 8注意:游戏会在有限次内结束,因为(设每轮游戏过后N个学生拥有糖果的最大数目为max,最小数目为min):(1)max不会增加;(2)min不会减少;(3)且任何一个糖果数多于min的学生,他的糖果数不会减少到min;(4)如果max和min不等,则至少有一个学生,他的糖果数会增加,这个学生就是糖果数最少的学生。解题分析:对于给定的学生人数N,以及初始时N个学生的糖果数,最终需要进行游戏的轮数以及最终每个学生的糖果数是没有规律可循的,只能进行模拟。模拟游戏的每一轮,直到N个学生的糖果数一样为止。以样例输入中的第1个测试数据为例解释游戏的过程,如图5.9所示,图(a)中圆圈里的数字表示初始时6个学生的糖果数,旁边的数字表示学生的序号(从0开始,按逆时针顺序排列)。图(b)表示第1轮游戏,每个人将手上糖果数的一半分给右边的学生(虚线箭头所示);如果某个学生手头上的糖果数位奇数,则由老师再给一块糖果凑成偶数块,如图(c)所示;第1轮游戏过后,每人手上的糖果数如图(d)所示。具体实现时,可以用一整型数组candys存储N个学生(序号为0N-1,如图5.9(a)所示)的糖果数。在模拟每一轮游戏时,要先用临时变量(设为half0)保存第N-1个学生糖果数的一半,然后将第i个学生的糖果数candysi更新为:candysi/2+candysi-1/2;最后一个学生,即第0个学生的糖果数更新为:candys0/2+half0。在判断N个学生的糖果数是否一致时,注意只要有前后两个学生的糖果数不一致的情况,就可以判断这N个学生的糖果数不一致;另外第N-1个学生右边相邻的学生是第0个学生,所以要取模,即要判断candysi与candys(i+1)%N是否相等
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026届内蒙古自治区化学高一上期中质量检测试题含解析
- 胸腹水恶性肿瘤诊疗进展
- 河南省周口市扶沟县包屯高级中学2026届化学高二第一学期期中教学质量检测模拟试题含解析
- 平衡车转弯课讲解
- 信贷审批个人征信解读
- 细胞基础讲解
- 国有集团有限公司2025年合规管理体系建设实施方案
- 外出学习归来汇报
- 社区医院建设汇报
- 学期成长汇报
- 【《惠东农商银行个人信贷业务发展现状及存在的问题和策略分析》15000字】
- 光伏项目开发培训课件
- 职业年金政策讲解
- 智联猎头企业薪酬调研白皮书-2025年年中盘点
- 基孔肯雅热、登革热等重点虫媒传染病防控技术试题
- 消防设施操作员(监控方向)中级模拟考试题及答案
- 艾梅乙反歧视培训课件
- GB/T 10069.3-2024旋转电机噪声测定方法及限值第3部分:噪声限值
- 中国农业银行笔试题库(含答案)
- GA 1808-2022军工单位反恐怖防范要求
- GB 9706.202-2021医用电气设备第2-2部分:高频手术设备及高频附件的基本安全和基本性能专用要求
评论
0/150
提交评论