算法竞赛入门经典第一章【小结与习题】

数据类型:

61的平方用int数据类型存已经溢出了,并且用-Wall还给出警告:test.c:7: warning: integer overflow in expression

61的平方用double没问题,修改程序时,只需要改111111*111111111111.0*111111就能正确运行了。

sqrt(-10)没有报错,输出是nan;而用"%d"来输出,警告类型不匹配,但能输出10位数,并且每次输出不同。猜想是溢出,换成“%lld”输出,结果前面高6位不变,后面似乎在一个范围内来回变化,但未发现不循环。这个有点意思。。。循环输出1000次,发现第一次与之后的不同,第二次到1000次都相同。再执行也是这个效果,每次执行的结果不一样。

 浮点数1.0/0.0结果是inf0.0/0.0结果是nan1/0报错

scanf()

可以滤空(空格tab回车符)

printf()

输出%d"%%d",输出“\n”"\\n",以此类推

实践能力:

问题1int型浮点数的最小值和最大值是多少?

[cpp] view plaincopy

1. #include <stdio.h>    

2. int    

3. main(void)    

4. {    

5.     int i;    

6.     

7.     for (i = 1; i > 0; i++) NULL;    

8.     printf("%d %d\n", i, i-1);    

9.     return 0;    

10.}    

这个方法最容易想到,但比较慢。原理就是一旦溢出变成负数,那么停止循环,i++也不会执行了,然后输出这个负数和比这个最小值还小的值,其实就是刚才溢出前的最大值

 

问题2double型浮点数能精确到多少位小数?或者,这个问题本身值得商权?

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     printf("%f", 10.0/3.0);  

7.     return 0;  

8. }  


输出默认是小数点后面有6位,改成"%.2lf"重新编译运行后保留2位,改成100呢?

输出:3.3333333333333334813630699500208720564842224121093750000000000000000000000000000000000000000000000000

那么是精确到15位?把10.0/3.0改成1.0/0.3呢?结果确实一样,改成20.0/3.0呢?

输出:6.6666666666666669627261399000417441129684448242187500000000000000000000000000000000000000000000000000

也是精确到15位。。。

 

问题3double型浮点数最大正数值和最小正数值分别是多少?(不必特别精确)

这里有一个精度的概念和溢出的概念,注意区分?

此题留白。

 

问题4

a&&b||c等效于(a&&b)||c

单独测试更快:先测试a&&b||ca b c分别赋值0 1 1如果是(a&&b)||c结果会是1,如果是a&&(b||c)结果会是0

结论就是&&优先级高于||0

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b, c;  

7.     a = 0, b = 1, c = 1;  

8.     printf("%d\n", a&&b||c);  

9.     return 0;  

10.}  

-Wall真强大,还会给出警告:warning: suggest parentheses around && within ||

再测试!a&&b,设置a b均为0,那么如果是!(a&&b)结果是1,如果是(!a)&&b结果是0

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b;  

7.       

8.     a = b = 0;  

9.     printf("%d\n", !a&&b);  

10.    return 0;  

11.}  


结果证明!优先级大于&&优先级。即!a&&b||c等效于((!a)&&b) || c

值得一提的是-Wall编译上面的程序时并没有给出警告,也就是说一般认为!&&||优先级高是非常明显的。

 

问题5

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b, x, y;  

7.       

8.     if (a)  

9.         if (b)  

10.            x++;  

11.        else  

12.            y++;  

13.    return 0;  

14.}  


虽然缩进使得逻辑关系比较明朗,但是还是容易给初学者带来困惑,用-Wall编译还给出了警告:warning: suggest explicit braces toavoid ambiguous 'else'

改成:

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b, x, y;  

7.       

8.     if (a) {  

9.         if (b)  

10.            x++;  

11.        else  

12.            y++;  

13.    }         

14.    return 0;  

15.}  


警告便消失了。

 

【上机练习】

习题1-1平均数(average)

输出3个整数,输出它们的平均值,保留3位小数。

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b, c;  

7.   

8.     scanf("%d%d%d", &a, &b, &c);  

9.     printf("%.3f\n", (a+b+c) / 3.0);  

10.    return 0;  

11.}  

注意:保留三位小数,用浮点数格式输出,(a+b+c)/3会是整型的,讲分子分母其中一个变成浮点数类型就可以了。或者使用强制类型转换,在进行运算前会转换了该类型。如:(double)(a+b+c)/ 3;

 

习题1-2温度(temperature)

输入华氏温度f,输出对应的摄氏温度c,保留3位小数。提示:c =  5(f-32)/9

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int f;  

7.   

8.     scanf("%d", &f);  

9.     printf("%.3f\n", 5.0*(f-32.0)/9.0);  

10.    return 0;  

11.}  

这里当然也可以用强制类型转换:printf("%.3f\n",(double)5*(f-32)/9);我想这里应当是把5转为浮点数,因为有了一个浮点数,其他的也就跟着变成了浮点数,最后进行浮点数的四则运算。而不是做完整型的四则运算后再转换为浮点数,这样已经丢失了“精度”。

 

习题1-3连续和(sum)

输入正整数n,输出1+2+...+n的值。提示:目标是解决问题,而不是练习编程。

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int n;  

7.       

8.     scanf("%d", &n);  

9.     printf("%d\n", (n*(n+1)) / 2);  

10.    return 0;  

11.}  

根据正写和反写序列可以得到上述公式,因为此处还没学for循环,直接用公式即可。

 

习题1-4正弦和余弦(sincos)

输入正整数n(n < 360),输出n度的正弦、余弦函数值。提示:使用数学函数。

[cpp] view plaincopy

1. #include <stdio.h>  

2. #include <math.h>  

3.   

4. int  

5. main(void)  

6. {  

7.     int n;  

8.     double x;  

9.     const double PI = 4.0 * atan(1.0);  

10.      

11.    scanf("%d", &n);  

12.    x = (n/180.0)*PI;  

13.    printf("%.3f\n%.3f\n", sin(x), cos(x));  

14.    return 0;  

15.}  

我们知道,sincos函数接受的参数单元是弧度,输入度就需要现转为弧度,我们知道或记住180度==PI即,这样根据作比就可以转换了。这里我保留3位小数。

 

习题1-5距离(distance)

输入4个浮点数x1, y1, x2, y2,输出平面坐标系中(x1, y1)(x2, y2)的距离。

[cpp] view plaincopy

1. #include <stdio.h>  

2. #include <math.h>  

3.   

4. int  

5. main(void)  

6. {  

7.     double x1, y1, x2, y2;  

8.     double dist;  

9.           

10.    scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);  

11.    dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));  

12.    printf("%.3f\n", dist);  

13.    return 0;  

14.}  



 

习题1-6 偶数(odd)

输入一个整数,判断它是否为偶数,如果是,则输出"yes",否则输出"no"。提示:可以用多种方法判断。

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int x;  

7.       

8.     scanf("%d", &x);  

9.     printf(0 == x%2 ? "yes\n" : "no\n");  

10.    return 0;  

11.}  

注意:这里用了一个三目运算符,它是C语言中最常用的运算符了。作用不难从程序中看出。


习题1-7打折(discount)

一件衣服95元,若消费满300元,可打八五折。输入购买衣服件数,输出需要支付的金额(单位:元),保留两位小数。

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int num;  

7.       

8.     scanf("%d", &num);  

9.     printf("%.2f\n", num > 4 ? 95*num*0.85 : 95.0*num);    

10.    return 0;  

11.}  



 

习题1-8 绝对值(abs)

输入一个浮点数,输出它的绝对值,保留两位小数。

[cpp] view plaincopy

1. #include <stdio.h>  

2. #include <stdlib.h>//can call abs();  

3. #include <math.h>//can call fabs();  

4. #define Abs(x) ( (x) > 0 ? (x) : (-(x))  )//define Abs();  

5.   

6. //a function for abs  

7. double  

8. Fabs(double x)  

9. {  

10.    return x > 0 ? x : -x;  

11.}  

12.  

13.int  

14.main(void)  

15.{  

16.    double x;  

17.      

18.    scanf("%lf", &x);     

19.    printf("%.2f\n", (double)abs(x));//wrong answer  

20.    printf("%.2f\n", fabs(x));  

21.    printf("%.2f\n", Abs(x));  

22.    printf("%.2f\n", Fabs(x));  

23.    return 0;  

24.}  

注意:这里用了四个abs函数,abs()在stdlib.h中定义,只能用于整型求绝对值。fabs函数本身适用于浮点数。宏定义的根据类型自适应,Fabs函数也要事先确定类型。如此看来还是宏定义的比较好用。

 

习题1-9三角形(triangle)

输入三角形三边长度值(均为正整数),判断它是否能为直角三角形的三个边长。如果可以,则输出"yes",如果不能,则输出“no”。如果根本无法构成三角形,则输出"not atriangle"

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int a, b, c;  

7.     int tmp;  

8.       

9.     scanf("%d%d%d", &a, &b, &c);  

10.      

11.    if (a < b) {  

12.        tmp = a;  

13.        a = b;  

14.        b = tmp;  

15.    }  

16.    if (a < c) {  

17.        tmp = a;  

18.        a = c;  

19.        c = tmp;  

20.    }  

21.    if (b < c) {  

22.        tmp = b;  

23.        b = c;  

24.        c = tmp;  

25.    }  

26.      

27.    if (b*b+c*c == a*a)  

28.        printf("yes\n");  

29.    else  

30.        printf(a >= b+c ? "not a triangle\n" : "no\n");  

31.      

32.    return 0;  

33.}  

用前面介绍的方法将三个正整数排个序(这里是非升序),然后方便进行判断,逻辑层次是,是直角三角形,不是直接三角形又包括:构不成三角形和其他情况。

 

习题1-10年份(year)

输入年份,判断是否为闰年。如果是,则输出"yes",否则输出"no"。提示:简单地判断除以4的余数是不够的。

[cpp] view plaincopy

1. #include <stdio.h>  

2.   

3. int  

4. main(void)  

5. {  

6.     int year;  

7.   

8.     scanf("%d", &year);  

9.     if ( year%400 == 0 || (year%4 == 0 && year%100 != 0) )  

10.        printf("yes\n");  

11.    else  

12.        printf("no\n");  

13.    return 0;  

14.}