第2章资料C语言第二章Word文档格式.docx
《第2章资料C语言第二章Word文档格式.docx》由会员分享,可在线阅读,更多相关《第2章资料C语言第二章Word文档格式.docx(44页珍藏版)》请在冰豆网上搜索。
}
说明:
对于i可以达到10.0,但永远不会与10相等,所以for循环是一个死循环。
对于float和dobule类型的数据不能直接用==和!
=来比较大小,即不要测试精确的浮点型数值,需要用精度比较,来测试一个可接受的数值范围。
如:
fabs(10-i)>
1e-5;
2.4.5小结
现在对本章介绍的循环总结如下:
(1)介绍了在编程中的一些经验,如使用计算器、累加器、以及“当前最小/最大值”这样的中间变量。
使用printf输出一些关键的中间变量能有效地帮助我们了解程序执行过程、发现错误。
(2)遇到问题需要自己分析和设计,可以先写出“伪代码”,然后转换成程序。
伪代码是为了让思路更清晰,突出主要矛盾。
(3)编写好程序后,测试显得相当重要。
如前面的例子中几乎都有陷阱:
运算结果溢出、运算时间过长等。
(4)再次强调:
编程不是看书看会的,也不是听课听会的,而是练会的。
2.4.6上机练习
习题2-1位数(digit)
输入一个不超过109的正整数,输出它的位数。
例如12735的位数是5。
请不要使用任何数学函数,只用四则运算和循环语句实现。
【分析】
采取的策略是不断地整除10,检查商是否大于10。
程序如下:
习题2-2水仙花数(daffodil)
输出100~999中的所有水仙花数。
若3位数ABC=A2+B2+C2,则称其为水仙花数。
例如153=13+53+33,所以153是水仙花数。
采取的策略是穷举100~999之内的所有数据,检查是否满足题目的要求。
/*ShineCheng注:
以下程序a,b,c变量名字取的不是很好,建议大家用更清晰的方法,如bai,shi,ge。
*/
intmain(){
intn,a,b,c;
/*n的百、十、个位*/
for(n=100;
n<
=999;
n=n+1){
a=n/100;
b=(n-a*100)/10;
/*也可以写成b=(n%100)/10;
*/
c=n%10;
if(n==a*a*a+b*b*b+c*c*c)/*算术运算的优先级要高于逻辑运算*/
printf("
n);
}
Return0;
习题2-3韩信点兵(hanxi)
相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。
输入3个非负整数a,b,c,表示每种队形排尾的人数(a<
3,b<
5,c<
7),输出总人数的最小值(或报告无解)。
已知总人数不小于10,不超过100。
样例输入:
216
样例输出:
41
213
Noanswer
采取的策略是用穷举法解题;
总人数(10,100]。
intmain(){
inta,/*三人一排,余a人*/
b,/*五人一排,余b人*/
c,/*七人一排,余c人*/
sum;
/*总人数*/
scanf("
%d%d%d"
&
a,&
b,&
c);
for(sum=10;
sum<
=100;
sum=sum+1){
if((sum%3==a)&
&
(sum%5==b)&
(sum%7==c)){
sum);
break;
}
if(sum>
100)printf("
Noanswer"
);
习题2-4倒三角形(triangle)
输入正整数n≤20,输出一个n层的倒三角形。
例如n=5时输出如下:
#########
#######
#####
###
#
该图形一共有n行,这次要考虑每行中,先输出若干个空格,所以,其外循环为:
for(i=1;
i<
=n;
i++){
输出若干个空格
输出若干#
换行
下面列出在第i行,其空格数,#字符数与i的关系为:
行i空格数#字符数
102n-1
212n-3
…
ii-12n-2i+1
n-1n-23
nn-11
即第i行的空格数为i-1个,#字符个数为2n-2i+1。
#字符个数为2n-2i+1是如何得来的呢?
如果将行从第n行记为第1行,第n-1行记为第2行,…,则原第i行现在记为第n-i+1行。
现在行号为第1行的#字符的个数为1,现在行号为第2行的#字符的个数为3=2*2-1,所以原第i行现在记为第n-i+1行,输出的#字符的个数为2(n-i+1)-1=2n-2i+1。
所以在第i行输出空格和输出#字符的内循环分别为:
for(j=1;
j<
=i-1;
j++)
printf("
"
=2n-2i+1;
%c"
'
#'
合起来,构成一个完整程序。
intn,/*输出n行;
=20*/
i,/*打印第i行*/
j;
for(i=1;
i<
i=i+1){
/*在第i行,打印(i-1)个空格*/
for(j=1;
j<
j=j+1)printf("
/*在第i行,打印(2*n-2*i+1)个#*/
=(2*n-2*i+1);
#"
\n"
/*输出结束后换行,否则所有的#号在同一行输出*/
引申1:
用for循环编程画出下列图形:
M
MM
MMM
MMMM
MMMMM
MMMMMM
MMMMMMM
MMMMMMMM
MMMMMMMMM
MMMMMMMMMM
该图形一共有10行,每一行增加一个字符,所以,应循环10次,每次输出一行,其循环模式为:
输出第i行
“输出第i行”是在for循环中的一个小循环。
每次执行“输出第i行”,其长度都是不一样的,但长度的变化正好与循环变量i同步,故可以依赖于i。
注意到第i行的M字符数与i的关系。
行iM数
111
222
333
101010
所以,可以得到“输出第i行”的循环为:
=i;
j++)printf(“%c”,’M’)
完整的程序如下:
intmain(){
inti,j;
for(i=1;
for(j=1;
M'
return0;
对付这种字符图形,一般用两重循环,外循环遍历所有行,内循环遍历行中每个字符。
引申2:
输出下列图形:
MMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMM
MMMMMMMMMMMMM
MMMMMMMMMMM
该图形一共有10行,这次要考虑每行中,先输出若干个空格,所以,其外循环为:
输出若干M
下面列出在第i行,其空格数,M数与i的关系为:
1019
2117
3215
4313
1091
即第i行的空格数为i-1个,M个数为21-2i。
即在第i行输出空格和输出M字符的内循环分别为:
printf(“”);
for(k=1;
k<
=21-2i;
k++)
printf(“%c”,’M’);
完整程序如下:
{
inti,j,k;
for(i=1;
i++)
{
for(k=1;
=21-2*i;
引申3:
A
ABC
ABCDE
ABCDEFG
ABCDEFGHI
ABCDEFGHIJK
ABCDEFGHIJKLM
ABCDEFGHIJKLMNO
ABCDEFGHIJKLMNOPQ
ABCDEFGHIJKLMNOPQRS
输出若干字符
如果要输出A起头依序的n(n<
27)个字母,可以为:
for(ch='
A'
;
ch<
'
+n;
++ch)
ch);
下面分析每一行中的空格数与字符数与第i行之间的关系:
191
283
375
467
10019
即第i行的空格数据为10-i个,字符数为2i-1。
因此,输出空格数和字符数的内循环分别为:
=10-i;
++j)/*输出空格数*/
+2*i-1;
完整程序如下:
inti,j;
charch;
for(ch='
++ch)/*输出字符*/
引申4:
*
***
*****
*******
上面的图形可以分成两部分:
(1)
*
与引申3的分析一样,输出空格数和字符数的内循环分别为:
=4-i;
=2*i-1;
++k)/*输出“*”号*/
*"
(2)
与引申2的分析一样,输出空格数和字符数的内循环分别为:
=7-2*i;
=4;
=3;
习题2-6调和级数(harmony)
输入一个正整数n,输出H(n)=
的值,保留3位小数。
例如n=3时答案为1.833。
本题主要考察循环语句的使用。
秘诀是要从绝对值最小的项开始向绝对值大的项累加。
unsignedintn;
/*我们认为int已经足够表达所谓的“正整数”范围*/
doublesum=0;
%u"
for(;
n>
=1;
n=n-1){
sum=sum+1.0/n;
%.3f"
习题2-7近似计算(approximation)
计算
,直到最后一项小于10-6。
intn;
intsymbol;
n=1000001;
/*显然,1/1000001小于0.000001*/
n=n-2){
if((n+1)/2%2==1)symbol=1;
elsesymbol=-1;
sum=sum+symbol*(1.0/n);
%.20lf"
习题2-8子序列的和(subsequence)
输入两个正整数n<
m<
106,输出
,保留5位小数。
例如,n=2,m=4时答案是0.42361;
n=65536,m=655360时答案为0.00001。
注意:
本题有陷阱。
所谓的陷阱,是指m的平方可能会导致整数溢出。
所以,另一个秘诀是,把m和n定义为double。
doublem,n;
%lf%lf"
n,&
m);
/*假设用户输入的n总是不大于m*/
m>
m=m-1){
sum=sum+1.0/(m*m);
/*注意,不能写成sum=1/m*m*/
%.5lf"
习题2-9分数化小数(decimal)
输入正整数a,b,c,输出a/b的小数形式,精确到小数点后c位。
a,b≤106,c≤100。
例如a=1,b=6,c=4时应输出0.1667。
注意到a,b,c均为正整数,所以输出结果的小数点后至少会有1位。
另外,从本题的示例输出中可以感知到,小数的最后一位,是要考虑到四舍五入进位的。
采取的策略是模拟整数除法的过程,利用整除所得的余数,不断地对目标结果求精。
inta,b,c;
%d."
a/b);
//先输出整数和小数点
for(inti=1;
=c;
i++)//按照除法规则进行相除运算
a=(a%b)*10;
//确定下次被除数
if(i!
=c)
else{//确定第c位小数是否需要进行四舍五入
a=(a%b)*10;
if(a/b>
=5)
printf("
a/b+1);
else
2.4.7ACM题目中的输入输出
1.ACM题目特点
由于ACM竞赛题目的输入数据和输出数据一般有多组(不定),并且格式多种多样,所以,如何处理题目的输入输出是对大家的一项最基本的要求。
这也是困扰初学者的一大问题。
经常有刚接触ACM在线测试系统的同学抱怨:
“为什么我在OJ(OnlineJudge)上连简单的A+B也通不过?
”
先给一个竞赛样例:
题目名称:
A+BforInput-OutputPractice(I)
链接地址:
TimeLimit:
1Seconds
MemoryLimit:
32768K
ProblemDescription
YourtaskistoCalculatea+b.
Tooeasy?
!
Ofcourse!
Ispeciallydesignedtheproblemforacmbeginners.
Youmusthavefoundthatsomeproblemshavethesametitleswiththisone,yes,alltheseproblemsweredesignedforthesameaim.
Input
Theinputwillconsistofaseriesofpairsofintegersaandb,separatedbyaspace,onepairofintegersperline.
Output
Foreachpairofinputintegersaandbyoushouldoutputthesumofaandbinoneline,andwithonelineofoutputforeachlineininput.
SampleInput
15
1020
SampleOutput
6
30
初学者很常见的一种写法:
inta,b;
scanf(“%d%d”,&
b);
printf(“%d”,a+b);
但上述代码提交上述到OJ上不能通过,是什么原因呢?
这就是下面需要解决的问题。
下面来分类进行介绍。
2.基本输入
(1)第一类输入
输入不说明有多少个InputBlock,以EOF为结束标志,例如上面的例子。
源代码如下:
while(scanf("
%d%d"
a,&
b)!
=EOF)printf("
a+b);
}
本类问题的输入方案为:
①C语法
while(scanf("
=EOF)
....
②C++语法
while(cin>
>
a>
b)
....
①scanf函数返回值就是读出的变量个数,如:
scanf("
b);
,如果只有一个整数输入,返回值是1;
如果有两个整数输入,返回值是2;
如果一个都没有,则返回值是-1。
②EOF是一个预定义的常量,等于-1。
(2)第二类输入
输入一开始就会说有n个InputBlock,下面接着是输入n个InputBlock。
参见:
HDOJ_1090(
intn,i,a,b;
for(i=0;
n;
scanf("
}
for(i=0;
n;
i++)
....
cin>
n;
(3)第三类输入
输入不说明有多少个InputBlock,但以某个特殊输入为结束标志。
HDOJ_1091(
intmain()
{
while(scanf("
b)&
(a!
=0&
b!
=0))
上面程序有什么问题?
while(scanf(“%d”,&
n)!
=EOF&
n!
=0)
n&
n!
=0)
(4)第四类输入
以上几种情况的组合,可以参照如下网页,进行上机实验。
①
②
③
(5)第五类输入
输入一整行的字符串。
HDOJ_1048(http: