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

数据类型:

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

6个1的平方用double没问题,修改程序时,只需要改111111*111111为111111.0*111111就能正确运行了。

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

 浮点数 1.0/0.0 结果是inf,0.0/0.0结果是nan,1/0报错

scanf():

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

printf():

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

实践能力:

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

#include <stdio.h>  
int  
main(void)  
{  
    int i;  
  
    for (i = 1; i > 0; i++) NULL;  
    printf("%d %d\n", i, i-1);  
    return 0;  
}  

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


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

#include <stdio.h>

int
main(void)
{
	printf("%f", 10.0/3.0);
	return 0;
}

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

输出:3.3333333333333334813630699500208720564842224121093750000000000000000000000000000000000000000000000000

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

输出:6.6666666666666669627261399000417441129684448242187500000000000000000000000000000000000000000000000000

也是精确到15位。。。


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

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

此题留白。


问题4:

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

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

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

#include <stdio.h>

int
main(void)
{
	int a, b, c;
	a = 0, b = 1, c = 1;
	printf("%d\n", a&&b||c);
	return 0;
}
-Wall真强大,还会给出警告: warning: suggest parentheses around && within ||

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

#include <stdio.h>

int
main(void)
{
	int a, b;
	
	a = b = 0;
	printf("%d\n", !a&&b);
	return 0;
}

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

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


问题5:

#include <stdio.h>

int
main(void)
{
	int a, b, x, y;
	
	if (a)
		if (b)
			x++;
		else
			y++;
	return 0;
}

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

改成:

#include <stdio.h>

int
main(void)
{
	int a, b, x, y;
	
	if (a) {
		if (b)
			x++;
		else
			y++;
	}		
	return 0;
}

警告便消失了。


【上机练习】

习题1-1 平均数(average)

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

#include <stdio.h>

int
main(void)
{
	int a, b, c;

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


习题1-2 温度(temperature)

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

#include <stdio.h>

int
main(void)
{
	int f;

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


习题1-3 连续和(sum)

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

#include <stdio.h>

int
main(void)
{
	int n;
	
	scanf("%d", &n);
	printf("%d\n", (n*(n+1)) / 2);
	return 0;
}
根据正写和反写序列可以得到上述公式,因为此处还没学for循环,直接用公式即可。


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

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

#include <stdio.h>
#include <math.h>

int
main(void)
{
	int n;
	double x;
	const double PI = 4.0 * atan(1.0);
	
	scanf("%d", &n);
	x = (n/180.0)*PI;
	printf("%.3f\n%.3f\n", sin(x), cos(x));
	return 0;
}
我们知道,sincos函数接受的参数单元是弧度,输入度就需要现转为弧度,我们知道或记住180度==PI即,这样根据作比就可以转换了。这里我保留3位小数。


习题1-5 距离(distance)

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

#include <stdio.h>
#include <math.h>

int
main(void)
{
	double x1, y1, x2, y2;
	double dist;
		
	scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
	dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
	printf("%.3f\n", dist);
	return 0;
}


习题1-6 偶数(odd)

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

#include <stdio.h>

int
main(void)
{
	int x;
	
	scanf("%d", &x);
	printf(0 == x%2 ? "yes\n" : "no\n");
	return 0;
}
注意:这里用了一个三目运算符,它是C语言中最常用的运算符了。作用不难从程序中看出。

习题1-7 打折(discount)

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

#include <stdio.h>

int
main(void)
{
	int num;
	
	scanf("%d", &num);
	printf("%.2f\n", num > 4 ? 95*num*0.85 : 95.0*num);	
	return 0;
}


习题1-8 绝对值(abs)

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

#include <stdio.h>
#include <stdlib.h>//can call abs();
#include <math.h>//can call fabs();
#define Abs(x) ( (x) > 0 ? (x) : (-(x))  )//define Abs();

//a function for abs
double
Fabs(double x)
{
	return x > 0 ? x : -x;
}

int
main(void)
{
	double x;
	
	scanf("%lf", &x);	
	printf("%.2f\n", (double)abs(x));//wrong answer
	printf("%.2f\n", fabs(x));
	printf("%.2f\n", Abs(x));
	printf("%.2f\n", Fabs(x));
	return 0;
}
注意:这里用了四个abs函数,abs()在stdlib.h中定义,只能用于整型求绝对值。fabs函数本身适用于浮点数。宏定义的根据类型自适应,Fabs函数也要事先确定类型。如此看来还是宏定义的比较好用。


习题1-9 三角形(triangle)

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

#include <stdio.h>

int
main(void)
{
	int a, b, c;
	int tmp;
	
	scanf("%d%d%d", &a, &b, &c);
	
	if (a < b) {
		tmp = a;
		a = b;
		b = tmp;
	}
	if (a < c) {
		tmp = a;
		a = c;
		c = tmp;
	}
	if (b < c) {
		tmp = b;
		b = c;
		c = tmp;
	}
	
	if (b*b+c*c == a*a)
		printf("yes\n");
	else
		printf(a >= b+c ? "not a triangle\n" : "no\n");
	
	return 0;
}
用前面介绍的方法将三个正整数排个序(这里是非升序),然后方便进行判断,逻辑层次是,是直角三角形,不是直接三角形又包括:构不成三角形和其他情况。


习题1-10 年份(year)

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

#include <stdio.h>

int
main(void)
{
	int year;

	scanf("%d", &year);
	if ( year%400 == 0 || (year%4 == 0 && year%100 != 0) )
		printf("yes\n");
	else
		printf("no\n");
	return 0;
}


你可能感兴趣的:(算法竞赛入门经典第1章【小结与习题】)