C站的小伙伴们大家好呀!我最近在学习刘汝佳老师的《算法竞赛入门经典》,跟着这本书来学习和做习题,在这里和大家一起分享进步。下面是本书的第一部分的语言篇。
语言篇——程序设计入门
- 算术表达式
- 变量及其输入
- 顺序结构程序设计
- 分支结构程序设计
- 输出实验
- 习题
算术表达式
#include<stdio.h>
int main(void)
{
printf("%d\n",8/2);
printf("%d\n",8/5);
printf("%d\n",(-8)/5);
printf("%d\n",8/(-5));
return 0;
}
运行结果如下:
那如何计算和输出8/5的值呢?
我们来看下面的程序:
#include<stdio.h>
int main(void)
{
printf("%.1f\n",8.0/5.0);
printf("%.2f\n",8.0/5.0);
printf("%.1f\n",8/5);
printf("%d\n",8.0/5.0);
return 0;
}
运行结果如下:
之所有有上面的输出,这是因为,在C语言中:
整数/整数=整数;
浮点数/浮点数=浮点数;
整数-浮点数=浮点数;
8和5被看作是整数,所以其商也为整数,1。
8.0和5.0被看作是浮点数,所以其商也是浮点数。
而%.1f和%.2f这里的"1"和"2"是小数点后的位数。
变量及其输入
#include <stdio.h>
int main(void)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",a+b);
return 0;
}
首先,声明两个整型变量a和b,然后利用scanf()函数从键盘读入数据并放到a和b中。
scanf的占位符和变量的数据类型应一一对应,且每个变量前需加"&"
符号。(可以把变量理解为"存放值的场所")在C语言中,变量有自己的数据类型,例如,int型变量存放整数值,而double型变量存放双精度浮点数。
例题1-1
输入底面半径r和高h,输出圆柱体的表面积,保留3位小数。
样例输入:
3.5 9
样例输出:
Area=274.889
分析
表面积=侧面积+底面积
×
2
\times 2
×2
我们先来看下面这样一个错误的程序:
#include <stdio.h>
#define PI 3.14
int main(void)
{
double r,h,s1,s2,Area;
scanf("%d%d",&r,&h);//输入半径和高
s1=2*PI*r*h;
s2=2*PI*r*r;
Area=s1+s2;
printf("Area=%.3lf\n",Area);
return 0;
}
错误原因:
代码实现
#include <stdio.h>
#define PI 3.14
int main(void)
{
double r,h,s1,s2,Area;
scanf("%lf%lf",&r,&h);//输入半径和高
s1=2*PI*r*h;//侧面积
s2=2*PI*r*r;//上底和下底底面积
Area=s1+s2;
printf("Area=%.3lf\n",Area);
return 0;
}
上述的代码中对于常量
π
\pi
π的处理是用宏定义来处理的。
编译程序时,所有的PI都会用3.14来替换,这一过程被称为编译时替换
。在运行程序时,程序中所有的替换均已完成。
#define指令还可定义字符和字符串常量。前者使用
单引号
,后者使用双引号
。如下所示:
#define ESC '\033'
#define OOPS "Now you have done it!"
此外,还可以利用关键字const类型限定符来定义常量。
const类型限定符
const所修饰的内容是不可变的,故只有可读性。
宏和const的区别是,在代码生成时所被处理的阶段不同,宏的替换在预编译
(预处理)阶段,而const 常量则在编译阶段
才确定,并分配内存。
const常量有数据类型
,而宏没有数据类型。编译器只对宏在预编译阶段进行替换
,却没有类型及安全检查,所以在替换过程中可能会出现错误。但是编译器却可以对const所定义的常量进行类型和安全检查,由宏引起的错误一般调试不出来,而const常量可以。
即,将上述代码改写为:
#include <stdio.h>
#include <math.h>
int main(void)
{
double r,h,s1,s2,Area;
const double PI = acos(-1.0);
scanf("%lf%lf",&r,&h);//输入半径和高
s1=2*PI*r*h;
s2=2*PI*r*r;
Area=s1+s2;
printf("Area=%.3lf\n",Area);
return 0;
}
补充:
接下来,我们看以下这条赋值语句
:
s1=2*PI*r*h;
对于赋值语句
,“赋值”是个动作,其确切的含义是,先计算右边的值,再赋值给左边的变量,覆盖它原来的值。变量是“喜新厌旧”的,即新的值将覆盖原来的值,一旦被赋予了新的值,变量中原来的值就丢失了。
顺序结构程序设计
例题1-2
输入一个三位数,分离出它的百位十位和个位,反转后输出。
样例输入:
127
样例输出:
721
分析
读入n,百位=n/100,十位=n/10%10,个位=n%10
代码实现
#include <stdio.h>
int main(void)
{
int n;
scanf("%d",&n);
printf("%d%d%d\n",n%10,n/10%10,n/100);
return 0;
}
这里有一个问题是,如果个位是0,例如输入250,输出052吗?
所以我们可以进一步改进:
方法一
#include <stdio.h>
int main(void)
{
int n,m;
scanf("%d",&n);
m=n%10*100+n/10%10*10+n/100;
printf("%d\n",m);
return 0;
}
这样如果是输入250,就会输出52。
若改变输出格式,也可以输出052。
printf("%03d\n",m);
方法二分支结构:
#include <stdio.h>
int main(void)
{
int n,m;
scanf("%d",&n);
if (n%10) //个位不等于0
printf("%d%d%d\n",n%10,n/10%10,n/100);
else if (n%10==0) //个位等于0
printf("%d%d\n",n/10%10,n/100);
return 0;
}
例题1-3
交换变量:输入两个整数m和n,交换二者的值,然后输出。
样例输入:
824 16
样例输出:
16 824
最简单的做法,输出时交换:
#include <stdio.h>
int main(void)
{
int n,m;
scanf("%d%d",&n,&m);
printf("%d %d \n",m,n);
return 0;
}
最经典的做法:三变量法:
#include <stdio.h>
int main(void)
{
int n,m,t;
scanf("%d%d",&n,&m);
t=n;n=m;m=t;
printf("%d %d\n",n,m);
return 0;
}
不借助任何变量,进行交换:
#include<stdio.h>
int main()
{
int m, n;
scanf("%d%d", &m, &n);
m = m + n;
n = m - n;
m = m - n;
printf("%d %d\n", m, n);
return 0;
}
分支结构程序设计
例题1-4
鸡兔同笼:
已知鸡和兔的总数量为n,总腿数为m。输入n和m,依次输出鸡的数目和兔的数目。如果无解,则输出No answer。
分析
假设鸡有a只,兔有b只,则a+b=n,2a+4b=m,联立解得a=(4n-m)/2,b=n-a。
怎样判断无解呢?
解出a或者b是负数。或者a或者b不是整数。
#include<stdio.h>
int main()
{
int a, b, n, m;
scanf("%d%d", &n, &m);
a = (4*n-m)/2; b = n-a;
if(m % 2 == 1 || a < 0 || b < 0) //短路的方法计算逻辑表达式
printf("No answer\n");
else
printf("%d %d\n", a, b);
return 0;
}
C语言中的逻辑运算符,都是短路运算符,一旦能确定整个表达式的值,就不再进行计算了。
例题1-5:三个整数排序
输入三个整数,从小到大排序后输出。
样例输入
20 7 33
样例输出
7 20 33
分析
方法一这三个数有可能的六种排序:
abc,acb,bac,bca,cab,cba,所以我们可以利用分支结构一一列出:
(这里需要注意的是,千万不要忽略等于即不仅仅有可能是a<b<c,也有可能a<=b<=c)
#include <stdio.h>
int main(void)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if (a<=b && b<=c)
printf("%d %d %d \n",a,b,c);
else if (a<=c && c<=b)
printf("%d %d %d \n",a,c,b);
else if (b<=a && a<=c)
printf("%d %d %d \n",b,a,c);
else if (b<=c && c<=a)
printf("%d %d %d \n",b,c,a);
else if (c<=a && c<=b)
printf("%d %d %d \n",c,a,b);
else if (c<=b && c<=a)
printf("%d %d %d \n",c,b,a);
return 0;
}
方法二
利用前面讲过的三变量交换法,先检查a和b,使得a是a和b中最小的数,然后再检查,a和c使得a是a和c中最小的数(即a,b,c中最小的数),然后再检查b和c,使得b是b和c中最小的数。
#include <stdio.h>
int main(void)
{
int a,b,c,t;
scanf("%d%d%d",&a,&b,&c);
if (a>b)
t=a;a=b;b=t;
if (a>c)
t=a;a=c;c=t;
if (b>c)
t=b;b=c;c=t;
printf("%d %d %d \n",a,b,c);
return 0;
}
输出实验
转义字符\n
#include <stdio.h>
int main(void)
{
printf("1\n2\n");
printf("1\n\n2\n");
return 0;
}
输出’’
#include <stdio.h>
int main(void)
{
printf("\\\n");//编译器会把双斜线理解成单个字符'\'
return 0;
}
表达式1/0 ,1.0/0.0,0.0/0.0
printf("%d",0.0/0.0);
printf("%d",1.0/0.0);
printf("%d",1/0);
系统都会报错:
divide or mod by zero
习题
习题1-1平均数(average)
输入3个整数,输出他们的平均值,保留3位整数。
#include <stdio.h>
int main(void)
{
double a,b,c;
scanf("%lf%lf%lf",&a,&b,&c);
printf("%.3lf\n",(a+b+c)/3);
return 0;
}
习题1-2温度(temperature)
输入华氏温度f,输出对应的摄氏温度c,保留3位小数。提示:c=5(f-32)/9。
#include <stdio.h>
int main(void)
{
double f;
scanf("%lf",&f);
printf("%.3lf\n",5*(f-32)/9);
return 0;
}
习题1-3连续和(sum)
输入正整数n,输出1+2+3+……+n。
#include <stdio.h>
int main(void)
{
int i,n,sum=0;
scanf("%d",&n);
for (i=1;i<=n;i++)
sum+=i;
printf("%d\n",sum);
return 0;
}
习题1-4正弦和余弦(sin和cos)
输入正整数n(n<360),输出n度的正弦、余弦函数值。
#include <stdio.h>
#include <math.h>
int main(void)
{
double n;
const double PI=3.1415;
scanf("%lf",&n);
printf("cos(%.1lf)=%lf,sin(%.1lf)=%lf\n",n,cos(n/180*PI),n,sin(n/180*PI));
return 0;
}
这里需要注意的是,输入的n是角度,而cos(),sin()函数的参数是弧度制的,所以需要转化。
习题1-5
一件衣服95元,若消费满300元,可打八五折。输入购买衣服件数,输出需要支付的金额(单位:元),保留两位小数。
#include <stdio.h>
int main(void)
{
int n;
scanf("%d",&n);
if (n*95>=300)
printf("%.2lf\n",n*95*0.85);
else
printf("%d\n",n*95);
return 0;
}
习题1-6 三角形(triangle)
输入三角形3条边的长度值(均为正整数),判断是否能为直角三角形
的3个边长。如果可以,则输出yes,如果不能,则输出no。
如果根本无法构成三角形,则输出not a triangle。
#include <stdio.h>
int main(void)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if (a+b<=c || a+c<=b || b+c<=a)//无法构成三角形
printf("not a triangle\n");
else if (a*a+b*b=c*c || a*a+c*c=b*b || b*b+c*c=a*a)//直角
printf("yes\n");
else
printf("no\n");
return 0;
}
习题1-7年份(year)
输入年份,判断是否为闰年。如果是,则输出yes,否则输出no。
判断闰年
能被4整除但不能被100整除,或者能被100整除。
#include <stdio.h>
int main(void)
{
int n;
scanf("%d",&n);
if (n/400==0 || (n%4==0 && n/100!=0))
printf("yes\n");
else
printf("np\n");
return 0;
}