算法与程序实践习题解答5模拟.docx
《算法与程序实践习题解答5模拟.docx》由会员分享,可在线阅读,更多相关《算法与程序实践习题解答5模拟.docx(92页珍藏版)》请在冰豆网上搜索。
算法与程序实践习题解答5模拟
《算法与程序实践》习题解答5——模拟
现实中的有些问题,难以找到公式或规律来解决,只能按照一定步骤,不停地做下去,最后才能得到答案。
这样的问题,用计算机来解决十分合适,只要能让计算机模拟人在解决此问题的行为即可。
这一类的问题可以称之为“模拟题”。
比如下面经典的约瑟夫问题:
讲课:
CS51CS52CS53
实验:
CS56CS516CS517
CS59CS513CS518
CS51:
约瑟夫问题
(来源:
2746,程序设计导引及在线实践(李文新)例6.1P141)
问题描述:
约瑟夫问题:
有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。
就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入:
每行是用空格分开的两个整数,第一个是n,第二个是m(0最后一行是:00输出:对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号。样例输入:621248300样例输出:517解题思路:初一看,很可能想把这道题目当作数学题来做,即认为结果也许会是以n和m为自变量的某个函数f(n,m),只要发现这个函数,问题就迎刃而解。实际上,这样的函数很难找,甚至也许根本就不存在。用人工解决的办法就是将n个数写在纸上排成一圈,然后从1开始数,每数到第m个就划掉一个数,一遍遍做下去,直到剩下最后一个。有了计算机,这项工作做起来就会快多了,我们只要编写一个程序,模拟人工操作的过程就可以了。用数组anLoop来存放n个数,相当于n个数排成的圈;用整型变量nPtr指向当前数到的数组元素,相当于人的手指;划掉一个数的操作,就用将一个数组元素置0的方法来实现。人工数的时候,要跳过已经被划掉的数,那么程序执行的时候,就要跳过为0的数组元素。需要注意的是,当nPtr指向anLoop中最后一个元素(下标n-1)时,再数下一个,则nPtr要指回到数组的头一个元素(下标0),这样anLoop才象一个圈。参考程序:#include#include#defineMAX_NUM300intaLoop[MAX_NUM+1];intmain(){intn,m,i;while(1){scanf("%d%d",&n,&m);if(n==0)break;for(i=0;iaLoop[i]=i+1;intnPtr=0;//存储位置信息for(i=0;i{intnCount=0;//记录本轮数到的猴子数目while(nCount{while(aLoop[nPtr]==0)//跳过已经出圈的猴子nPtr=(nPtr+1)%n;//到下一个位置,如果到最后就跳到第1个nCount++;nPtr=(nPtr+1)%n;}nPtr--;//找到要出圈的猴子,位置要回退一个if(nPtr<0)nPtr=n-1;if(i==n-1)//最后一个出圈的猴子printf("%d\n",aLoop[nPtr]);aLoop[nPtr]=0;}}return0;}注意事项:上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0的数组元素,因此算法的效率不是很高。后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。n个元素的数组,从下标0的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+1)%n”。这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。对于本题,虽然很难直接找出结果函数f(n,m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放n个数。请写出这个高效而节省空间的程序。问题一:在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。比如,语句15,循环是从0到n-1,而不是从0到n。问题二:nPtr--到nPtr=n-1回退一个位置,易被忽略或写错。比如只写了语句nPtr--,忘了处理nPtr变成小于0的情况。CS52:花生问题(同CS93)(来源:2950,程序设计导引及在线实践(李文新)例4.3P107)问题描述:鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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表示该植株下没有花生。输出:输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。样例输入:672100000000000130000000070150000000090000000000样例输出:37解题思路:试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。结果只能是做了才知道。即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。参考程序:#include#include#include#includeintT,M,N,K;#defineMAX_NUM55intaField[MAX_NUM][MAX_NUM];intmain(){inti,j,t,m,n;scanf("%d",&T);for(t=0;t{scanf("%d%d%d",&M,&N,&K);for(m=1;m<=M;m++)for(n=1;n<=N;n++)scanf("%d",&aField[m][n]);intnTotalPeanuts=0;//摘得的花生总数intnTotalTime=0;//已经花去的总时间intnCuri=0,nCurj;//当前位置坐标while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
最后一行是:
00
输出:
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号。
样例输入:
62
124
83
样例输出:
5
1
7
解题思路:
初一看,很可能想把这道题目当作数学题来做,即认为结果也许会是以n和m为自变量的某个函数f(n,m),只要发现这个函数,问题就迎刃而解。
实际上,这样的函数很难找,甚至也许根本就不存在。
用人工解决的办法就是将n个数写在纸上排成一圈,然后从1开始数,每数到第m个就划掉一个数,一遍遍做下去,直到剩下最后一个。
有了计算机,这项工作做起来就会快多了,我们只要编写一个程序,模拟人工操作的过程就可以了。
用数组anLoop来存放n个数,相当于n个数排成的圈;用整型变量nPtr指向当前数到的数组元素,相当于人的手指;划掉一个数的操作,就用将一个数组元素置0的方法来实现。
人工数的时候,要跳过已经被划掉的数,那么程序执行的时候,就要跳过为0的数组元素。
需要注意的是,当nPtr指向anLoop中最后一个元素(下标n-1)时,再数下一个,则nPtr要指回到数组的头一个元素(下标0),这样anLoop才象一个圈。
参考程序:
#include
#defineMAX_NUM300
intaLoop[MAX_NUM+1];
intmain()
{
intn,m,i;
while
(1)
scanf("%d%d",&n,&m);
if(n==0)break;
for(i=0;iaLoop[i]=i+1;intnPtr=0;//存储位置信息for(i=0;i{intnCount=0;//记录本轮数到的猴子数目while(nCount{while(aLoop[nPtr]==0)//跳过已经出圈的猴子nPtr=(nPtr+1)%n;//到下一个位置,如果到最后就跳到第1个nCount++;nPtr=(nPtr+1)%n;}nPtr--;//找到要出圈的猴子,位置要回退一个if(nPtr<0)nPtr=n-1;if(i==n-1)//最后一个出圈的猴子printf("%d\n",aLoop[nPtr]);aLoop[nPtr]=0;}}return0;}注意事项:上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0的数组元素,因此算法的效率不是很高。后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。n个元素的数组,从下标0的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+1)%n”。这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。对于本题,虽然很难直接找出结果函数f(n,m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放n个数。请写出这个高效而节省空间的程序。问题一:在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。比如,语句15,循环是从0到n-1,而不是从0到n。问题二:nPtr--到nPtr=n-1回退一个位置,易被忽略或写错。比如只写了语句nPtr--,忘了处理nPtr变成小于0的情况。CS52:花生问题(同CS93)(来源:2950,程序设计导引及在线实践(李文新)例4.3P107)问题描述:鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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表示该植株下没有花生。输出:输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。样例输入:672100000000000130000000070150000000090000000000样例输出:37解题思路:试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。结果只能是做了才知道。即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。参考程序:#include#include#include#includeintT,M,N,K;#defineMAX_NUM55intaField[MAX_NUM][MAX_NUM];intmain(){inti,j,t,m,n;scanf("%d",&T);for(t=0;t{scanf("%d%d%d",&M,&N,&K);for(m=1;m<=M;m++)for(n=1;n<=N;n++)scanf("%d",&aField[m][n]);intnTotalPeanuts=0;//摘得的花生总数intnTotalTime=0;//已经花去的总时间intnCuri=0,nCurj;//当前位置坐标while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
aLoop[i]=i+1;
intnPtr=0;//存储位置信息
for(i=0;i{intnCount=0;//记录本轮数到的猴子数目while(nCount{while(aLoop[nPtr]==0)//跳过已经出圈的猴子nPtr=(nPtr+1)%n;//到下一个位置,如果到最后就跳到第1个nCount++;nPtr=(nPtr+1)%n;}nPtr--;//找到要出圈的猴子,位置要回退一个if(nPtr<0)nPtr=n-1;if(i==n-1)//最后一个出圈的猴子printf("%d\n",aLoop[nPtr]);aLoop[nPtr]=0;}}return0;}注意事项:上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0的数组元素,因此算法的效率不是很高。后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。n个元素的数组,从下标0的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+1)%n”。这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。对于本题,虽然很难直接找出结果函数f(n,m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放n个数。请写出这个高效而节省空间的程序。问题一:在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。比如,语句15,循环是从0到n-1,而不是从0到n。问题二:nPtr--到nPtr=n-1回退一个位置,易被忽略或写错。比如只写了语句nPtr--,忘了处理nPtr变成小于0的情况。CS52:花生问题(同CS93)(来源:2950,程序设计导引及在线实践(李文新)例4.3P107)问题描述:鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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表示该植株下没有花生。输出:输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。样例输入:672100000000000130000000070150000000090000000000样例输出:37解题思路:试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。结果只能是做了才知道。即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。参考程序:#include#include#include#includeintT,M,N,K;#defineMAX_NUM55intaField[MAX_NUM][MAX_NUM];intmain(){inti,j,t,m,n;scanf("%d",&T);for(t=0;t{scanf("%d%d%d",&M,&N,&K);for(m=1;m<=M;m++)for(n=1;n<=N;n++)scanf("%d",&aField[m][n]);intnTotalPeanuts=0;//摘得的花生总数intnTotalTime=0;//已经花去的总时间intnCuri=0,nCurj;//当前位置坐标while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
intnCount=0;//记录本轮数到的猴子数目
while(nCount{while(aLoop[nPtr]==0)//跳过已经出圈的猴子nPtr=(nPtr+1)%n;//到下一个位置,如果到最后就跳到第1个nCount++;nPtr=(nPtr+1)%n;}nPtr--;//找到要出圈的猴子,位置要回退一个if(nPtr<0)nPtr=n-1;if(i==n-1)//最后一个出圈的猴子printf("%d\n",aLoop[nPtr]);aLoop[nPtr]=0;}}return0;}注意事项:上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0的数组元素,因此算法的效率不是很高。后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。n个元素的数组,从下标0的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+1)%n”。这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。对于本题,虽然很难直接找出结果函数f(n,m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放n个数。请写出这个高效而节省空间的程序。问题一:在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。比如,语句15,循环是从0到n-1,而不是从0到n。问题二:nPtr--到nPtr=n-1回退一个位置,易被忽略或写错。比如只写了语句nPtr--,忘了处理nPtr变成小于0的情况。CS52:花生问题(同CS93)(来源:2950,程序设计导引及在线实践(李文新)例4.3P107)问题描述:鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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表示该植株下没有花生。输出:输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。样例输入:672100000000000130000000070150000000090000000000样例输出:37解题思路:试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。结果只能是做了才知道。即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。参考程序:#include#include#include#includeintT,M,N,K;#defineMAX_NUM55intaField[MAX_NUM][MAX_NUM];intmain(){inti,j,t,m,n;scanf("%d",&T);for(t=0;t{scanf("%d%d%d",&M,&N,&K);for(m=1;m<=M;m++)for(n=1;n<=N;n++)scanf("%d",&aField[m][n]);intnTotalPeanuts=0;//摘得的花生总数intnTotalTime=0;//已经花去的总时间intnCuri=0,nCurj;//当前位置坐标while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
while(aLoop[nPtr]==0)//跳过已经出圈的猴子
nPtr=(nPtr+1)%n;//到下一个位置,如果到最后就跳到第1个
nCount++;
nPtr=(nPtr+1)%n;
}
nPtr--;//找到要出圈的猴子,位置要回退一个
if(nPtr<0)
nPtr=n-1;
if(i==n-1)//最后一个出圈的猴子
printf("%d\n",aLoop[nPtr]);
aLoop[nPtr]=0;
return0;
注意事项:
上面的程序完全模拟了人工操作的过程,但因为要反复跳过为0的数组元素,因此算法的效率不是很高。
后文的“链表”一章,采用单链表进行模拟来解决本题,就能省去跳过已出圈的猴子这个操作,大大提高了效率。
n个元素的数组,从下标0的元素开始存放猴子编号,则循环报数的时候,下一个猴子的下标就是“(当前猴子下标+1)%n”。
这种写法比用分支语句来决定下个猴子的下标是多少,更快捷而且写起来更方便。
对于本题,虽然很难直接找出结果函数f(n,m),但是如果仔细研究,找出局部的一些规律,比如,每次找下一个要出圈的猴子时,直接根据本次的起点位置就用公式算出下一个要出圈的猴子的位置,那么写出的程序就可以省去数m只猴子这个操作,大大提高效率,甚至不需要用数组来存放n个数。
请写出这个高效而节省空间的程序。
问题一:
在数组里循环计数的时候,一定要小心计算其开始的下标和终止的下标。
比如,语句15,循环是从0到n-1,而不是从0到n。
问题二:
nPtr--到nPtr=n-1回退一个位置,易被忽略或写错。
比如只写了语句nPtr--,忘了处理nPtr变成小于0的情况。
CS52:
花生问题(同CS93)
2950,程序设计导引及在线实践(李文新)例4.3P107)
鲁宾逊先生有一只宠物猴,名叫多多。
这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:
“欢迎免费品尝我种的花生!
——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。
在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格(如图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表示该植株下没有花生。
输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。
6721
0000000
00001300
0000007
01500000
0009000
37
试图找规律,得到一个以花生矩阵作为自变量的公式来解决这个问题,是不现实的。
结果只能是做了才知道。
即走进花生地,每次要采下一株花生之前,先计算一下,剩下的时间,够不够走到那株花生,采摘,并从那株花生走回到路上。
如果时间够,则走过去采摘;如果时间不够,则采摘活动到此结束。
intT,M,N,K;
#defineMAX_NUM55
intaField[MAX_NUM][MAX_NUM];
inti,j,t,m,n;
scanf("%d",&T);
for(t=0;t{scanf("%d%d%d",&M,&N,&K);for(m=1;m<=M;m++)for(n=1;n<=N;n++)scanf("%d",&aField[m][n]);intnTotalPeanuts=0;//摘得的花生总数intnTotalTime=0;//已经花去的总时间intnCuri=0,nCurj;//当前位置坐标while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
scanf("%d%d%d",&M,&N,&K);
for(m=1;m<=M;m++)
for(n=1;n<=N;n++)
scanf("%d",&aField[m][n]);
intnTotalPeanuts=0;//摘得的花生总数
intnTotalTime=0;//已经花去的总时间
intnCuri=0,nCurj;//当前位置坐标
while(nTotalTime{intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置//寻找下一个最大花生数目及其位置for(i=1;i<=M;i++){for(j=1;j<=N;j++){if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
intnMax=0,nMaxi,nMaxj;//最大的花生数目,及其所处的位置
//寻找下一个最大花生数目及其位置
for(i=1;i<=M;i++)
for(j=1;j<=N;j++)
if(nMax{nMax=aField[i][j];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+=aField[nMaxi][nMaxj];aField[nMaxi][nMaxj]=0;//摘走花生赋值为0}elsebreak;}printf("%d\n",nTotalPeanuts);}return0;}实现技巧:用二维数组存放花生地的信息是很自然的想法。然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。常见问题:问题一:读题时应该仔细读。有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。问题二:有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。问题三:这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。CS53:显示器(见CS327)(来源:2745,程序设计导引及在线实践(李文新)例6.3P147)问题描述:你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。输入:输入文件包含多行,每一行为需要显示的数。每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。n为要显示的数值,s是显示的大小。输入文件的最后一行为两个0,这一行不需要处理。输出:以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。数值中的每个数字占s+2列,2s+3行。在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。每两个数字之间仅有一个空列。(样例输出中给出了0~9每个数字的输出格式)每个数值之后输出一个空行。样例输入:21234536789000样例输出:------||||||||||||--------||||||||||---------------------||||||||||||||||||||||||---------||||||||||||||||||||||||------------解题分析:一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:图5-3显示单元的笔画那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。注意,每个笔画都是由s个’-‘或s个’|’组成。输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:charn1[11]={"--------"};其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。如果是,则n1[i]为'-',如果否,则n1[i]为空格。上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:charn2[11]={"||||||"};该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。参考程序://显示器(见CS327)2745#include#includecharn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖intmain(){ints;charszNumber[20];intnDigit,nLength,i,j,k;while(1){scanf("%d%s",&s,szNumber);if(s==0)break;nLength=strlen(szNumber);//输出所有数字的笔画1for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
nMax=aField[i][j];
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+=aField[nMaxi][nMaxj];
aField[nMaxi][nMaxj]=0;//摘走花生赋值为0
else
printf("%d\n",nTotalPeanuts);
实现技巧:
用二维数组存放花生地的信息是很自然的想法。
然而,用aField[0][0]还是aField[1][1]对应花生地的左上角,是值得思考一下的。
因为从地里到路上还需要1个单位时间,题目中的坐标又都是从1开始,所以若aField[1][1]对应花生地的左上角,则从aField[i][j]点,回到路上所需时间就是i,这样更为方便和自然,不易出错。
并不是C/C++的数组下标从0开始,我们使用数组的时候,就要从下标为0的元素开始用。
常见问题:
读题时应该仔细读。
有的同学没有看到每次只能拿剩下花生株中最大的,而是希望找到一种在规定时间内能够拿最多花生的组合,把题目变成了另外一道题。
有的同学没有读到“没有两株花生株的花生数目相同”的条件,因此把题目复杂化了。
问题三:
这个题目是假设猴子在取花生的过程中不会回到大路上的,有些同学在思考是否可能在中间回到大路上,因为题目没说在大路上移动要花时间,所以有可能中途出来再进去摘的花生更多。
CS53:
显示器(见CS327)
2745,程序设计导引及在线实践(李文新)例6.3P147)
你的一个朋友刚买了一台新电脑,之前,他用过的最好的电脑只能是便携式计数器。
现在,你的朋友看着他的新电脑,他很失望,因为他喜欢他的计数器的LC显示器。
因此你决定给你的朋友编写一个程序模拟LC显示器来显示数字。
输入文件包含多行,每一行为需要显示的数。
每一行中有两个整数s和n,1<=s<=10,0<=n<=99999999。
n为要显示的数值,s是显示的大小。
输入文件的最后一行为两个0,这一行不需要处理。
以LC显示器方式输出输入文件中的数,用符号“-”表示水平的线段,用符号“|”表示垂直的线段。
数值中的每个数字占s+2列,2s+3行。
在输出时,对每两个数字之间的空白区域,要确保用空格填满,对最后一位数字之后的空白区域,不能输出空格。
每两个数字之间仅有一个空列。
(样例输出中给出了0~9每个数字的输出格式)
每个数值之后输出一个空行。
212345
367890
------
||||||
--------
|||||
---------------
||||||||
---------
------------
解题分析:
一个计算器上的数字显示单元,可以看作由以下编号从1到7的7个笔画组成:
图5-3显示单元的笔画
那么,我们可以说,数字8覆盖了所有的笔画,数字7覆盖笔画1、3和6,而数字1覆盖笔画3、6。
注意,每个笔画都是由s个’-‘或s个’|’组成。
输出时,先输出第1行,即整数n中所有数字里的笔画1,然后输出第2行到第s+1行,即所有数字的笔画2和笔画3,接下来是第s+2行,即所有数字的笔画4,再接下来是第s+3行到2×s+2行,,就是所有数字的笔画5和笔画6,最后的第2×s+3行,是所有数字的笔画7。
如果某个数字d没有覆盖某个笔画m(m=1…7),那么,输出数字d的笔画m的时候,就应该都输出空格;如果覆盖了笔画m,则输出s个’-‘或s个’|’,这取决于笔画m是横的还是竖的。
由上思路,解决这道题目的关键,就在于如何记录每个数字都覆盖了哪些笔画。
实际上,如果我们记录的是每个笔画都被哪些数字覆盖,则程序实现起来更为容易。
一个笔画被哪些数字所覆盖,可以用一个数组来记录,比如记录笔画1覆盖情况的数组如下:
charn1[11]={"--------"};
其中,n1[i](i=0……9)代表笔画1是否被数字i覆盖。
如果是,则n1[i]为'-',如果否,则n1[i]为空格。
上面的数组的值体现了笔画1被数字0,2,3,5,6,7,8,9覆盖。
对于竖向的笔画2,由字符'|'组成,则记录其覆盖情况的数组如下:
charn2[11]={"||||||"};
该数组的值体现了笔画2被数字0,4,5,6,8,9覆盖。
//显示器(见CS327)2745
charn1[11]={"--------"};//笔画1被数字0,2,3,5,6,7,8,9覆盖
charn2[11]={"||||||"};//笔画2被数字0,4,5,6,8,9覆盖
charn3[11]={"||||||||"};//笔画3被数字0,1,2,3,4,7,8,9覆盖
charn4[11]={"-------"};//笔画4被数字2,3,4,5,6,8,9覆盖
charn5[11]={"||||"};//笔画5被数字0,2,6,8覆盖
charn6[11]={"|||||||||"};//笔画6被数字0,1,3,4,5,6,7,8,9覆盖
charn7[11]={"-------"};//笔画7被数字0,2,3,5,6,8,9覆盖
ints;
charszNumber[20];
intnDigit,nLength,i,j,k;
scanf("%d%s",&s,szNumber);
if(s==0)
nLength=strlen(szNumber);
//输出所有数字的笔画1
for(i=0;i{if(i!=0)printf("");nDigit=szNumber[i]-'0';printf("");for(j=0;jprintf("%c",n1[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
if(i!
=0)printf("");
nDigit=szNumber[i]-'0';
printf("");
for(j=0;j
printf("%c",n1[nDigit]);
printf("\n");
for(i=0;i
for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n2[nDigit]);for(k=0;kprintf("");//笔画2和笔画3之间的空格printf("%c",n3[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
if(j!
nDigit=szNumber[j]-'0';
printf("%c",n2[nDigit]);
for(k=0;k
printf("");//笔画2和笔画3之间的空格
printf("%c",n3[nDigit]);
for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n4[nDigit]);printf("");}printf("\n");for(i=0;i{for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
printf("%c",n4[nDigit]);
for(j=0;j{if(j!=0)printf("");nDigit=szNumber[j]-'0';printf("%c",n5[nDigit]);for(k=0;kprintf("");printf("%c",n6[nDigit]);}printf("\n");}for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
printf("%c",n5[nDigit]);
printf("%c",n6[nDigit]);
for(i=0;i{if(i!=0)printf("");printf("");nDigit=szNumber[i]-'0';for(j=0;jprintf("%c",n7[nDigit]);printf("");}printf("\n");printf("\n");}return0;}实现技巧:一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:charn1[11]={"--------"};这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。常见问题:问题一:没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。于是想一个数字一个数字地从左到右输出,编了一阵才发现不对。问题二:忘了输出空格。应把所有的空白用空格符填充。例如:若要输出4的话就是这样:(。表示空格)。。。。||||--。。。。|。。。|。。。。问题三:两组数据之间要加一个空行。解题分析:用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。注意:两个数字之间有空列,但最后一个数字后没有。另外最后一个数字后也没有任何空白区域。参考程序(zzg):#include#includechardigit[10][5][4]={//存放0~9{"-","||","","||","-"},//0{"","|","","|",""},//1{"-","|","-","|","-"},//2{"-","|","-","|","-"},//3{"","||","-","|",""},//4{"-","|","-","|","-"},//5{"-","|","-","||","-"},//6{"-","|","","|",""},//7{"-","||","-","||","-"},//8{"-","||","-","|","-"}//9};intmain(){ints;//存储scharn[10];//用来存储n,要显示的数值inti,j,k,m;intlen;//用来存储n的长度//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);while(1){scanf("%d%s",&s,n);if(s==0)break;len=strlen(n);for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍{if(i==1||i==3)//第2行{for(j=1;j<=s;j++){for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
printf("%c",n7[nDigit]);
一个笔画被哪些数字所覆盖,最直接的想法是用整型数组来记录,比如:
intn1[10]={1,0,1,1,0,1,1,1,1,1};表示笔画1的被覆盖情况。
可是与其在数字i的笔画1所处的位置进行输出的时候,根据n1[i]的值决定输出空格还是'-’,还不如直接用下面的char类型数组来表示覆盖情况:
这样,在数字i的笔画1所处的位置进行输出的时候,只要输出s个n1[i]就行了。
这是一个很好的思路,它提醒我们,以后在编程时设置一些标志的时候,要考虑一下是否可以直接用更有意义的东西将0,1这样的标志代替。
没有注意到输出是按行,即先输出所有数字的第一画,再输出第二画……。
于
是想一个数字一个数字地从左到右输出,编了一阵才发现不对。
忘了输出空格。
应把所有的空白用空格符填充。
例如:
若要输出4的话就是这样:
(。
表示空格)
。
||
--。
|
两组数据之间要加一个空行。
用一个三维数组把0~9共10个数字的字符形式存放起来,这个数组可以定义为digit[10][5][4],第1维10代表10个数字,第2维5代表5行,第3维4代表3列加上一个字符串结束标志。
注意:
两个数字之间有空列,但最后一个数字后没有。
另外最后一个数字后也没有任何空白区域。
参考程序(zzg):
chardigit[10][5][4]={//存放0~9
{"-","||","","||","-"},//0
{"","|","","|",""},//1
{"-","|","-","|","-"},//2
{"-","|","-","|","-"},//3
{"","||","-","|",""},//4
{"-","|","-","|","-"},//5
{"-","|","-","||","-"},//6
{"-","|","","|",""},//7
{"-","||","-","||","-"},//8
{"-","||","-","|","-"}//9
};
ints;//存储s
charn[10];//用来存储n,要显示的数值
inti,j,k,m;
intlen;//用来存储n的长度
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d%s",&s,n);
if(s==0)break;
len=strlen(n);
for(i=0;i<5;i++)//输出5行,其中第2行和第4行需要输出s倍
if(i==1||i==3)//第2行
for(j=1;j<=s;j++)
for(k=0;k{printf("%c",digit[n[k]-'0'][i][0]);for(m=1;m<=s;m++)printf("%c",digit[n[k]-'0'][i][1]);printf("%c",digit[n[k]-'0'][i][2]);if(k}printf("\n");
printf("%c",digit[n[k]-'0'][i][0]);
for(m=1;m<=s;m++)
printf("%c",digit[n[k]-'0'][i][1]);
printf("%c",digit[n[k]-'0'][i][2]);
if(k}printf("\n");
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1