目录
TEXT 1 (等差数列求合)
计算1+2+3+...+100的合
#include<stdio.h>
int main()
{
int i = 0;
int sum = 0;
for (i = 1; i <= 100; i++)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
这里sum+=i与sum=sum+i的意思完全一致,表示为将变量i的值加到sum上。
TEXT 2 (打印素数)
打印100~200之间的所有素数
#include<math.h>
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i = 100; i <= 200; i++)
{
int num = 0;//计数,每次循环开始时归零
for (j = 2; j <= sqrt(i); j++)
{
if (i % j == 0)
{
num++;
}
}
if (num == 0)
{
printf("%d\n", i);
}
}
return 0;
}
如果一个数x是非素数,那么必然有(其中一个因子)<=(x的开方)。
例如:16,组成16的可能性有三种:1和16、2和8、4和4,这里1、2、4均小于等于16的开方,也就是4;当16能被1、2、4整除时,也必能被16、8和4整除。所以在写代码找因子时,只需要找到其平方根即可停止。
sqrt为开平方,一般格式为sqrt(),其头文件是<math.h>,返回值为double类型,可以用整型变量接收sqrt的返回值。
TEXT 3 (求最大公约数)
输入两个正整数,求最大公约数。
#include<stdio.h>
int main()
{
int a = 0, b = 0;
scanf("%d%d", &a, &b);
if (a < b)//将大数给a,小数给b
{
int i = a;
a = b;
b = i;
}
while (1)
{
int c = 0;
if (a % b != 0)
{
c = b;
b = a % b;
a = b;
}
else
{
printf("%d\n", b);
break;
}
}
return 0;
}
利用辗转相除法是可以最快得到最大公约数的,这里while(1)设置成死循环,找到最大公约数时break跳出循环,任何两个正整数都有公约数1,不用担心程序死循环。
介绍一下辗转相除法:例如求40和14的最大公约数
注意:辗转相除法必须是大数除以小数!所以在输入完两个数后,判断一下,将大的数赋给a,小的数赋给b。
TEXT 4 (打印1000~2000之间的闰年)
打印1000~2000年之间的闰年
#include<stdio.h>
int main()
{
int year = 0;
int count = 0;
for (year = 1000; year <= 2000; year += 4)
{
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
{
printf("%d ", year);
count++;
}
}
printf("\n1000年到2000年之间有%d个闰年\n", count);//243
return 0;
}
闰年:四年一闰,百年不闰,四百年一闰。
用count计数,每打印一次闰年+1,最后得出1000~2000年之间有243个闰年。
因为year在for循环中初始化为1000,1000能够整除4,所以每次循环之后year+=4,这样可以大大减少循环次数。
TEXT 5 (求增长率)
假设我国国民生产总值年增长率为r=9%,计算n=10年后我国的国民生产总值比现在相比,增长了百分之多少。公式为:。
#include<math.h>
#include<stdio.h>
int main()
{
int n = 10;
double r = 0.09;
double p = pow((1+r), n);
printf("十年后增长的百分比为%.0lf%%\n", p*100);
return 0;
}
求次方需要用到函数pow,pow函数的一般格式为pow(a,b),这里a为底数,b为指数。使用pow函数需包含头文件<math.h>。因为求的是百分比,打印时需要将p*100,并且将小数部分省略。
TEXT 6 (逆序打印)
给定整数,将其逆序打印。
#include<stdio.h>
int main()
{
int num = 12345678;
while (1)
{
if (num / 10 != 0)
{
printf("%d", num % 10);
num=num/10;
}
else
{
printf("%d", num);
break;
}
}
return 0;
}
如何得到最后一个数?(例如124)
- 第一次循环:124%10=4,将4打印,124/10=12;
- 第二次循环:12%10=2,将2打印,1/10=0;
- 最后:0%10=0,进入else,打印1,break跳出循环;
- 屏幕上显示的便是421了。
TEXT 7 (圆塔范围问题)
4个半径为1的圆塔,其圆心的坐标分别为:(2,2)、(-2,2)、(-2,-2)、(2,-2)。除圆塔外,其余地方均为空地。现输入坐标x、y,判断该点是否在圆塔内(包括边界)。
#include<stdio.h>
#include<math.h>
int main()
{
double x = 0.0, y = 0.0;
scanf("%lf%lf", &x, &y);
double d1 = sqrt(pow((x - 2), 2) + pow((y - 2), 2));
double d2 = sqrt(pow((x + 2), 2) + pow((y - 2), 2));
double d3 = sqrt(pow((x + 2), 2) + pow((y + 2), 2));
double d4 = sqrt(pow((x - 2), 2) + pow((y + 2), 2));
if (d1 > 1 && d2 > 1 && d3 > 1 && d4 > 1)
{
printf("该点位在空地上\n");
}
else
{
printf("该点位在圆塔上\n");
}
return 0;
}
计算点(x、y)到四个圆心的距离(sqrt和pow上面有讲,记得包含头文件<math.h>),如果四个距离均大于1(圆的半径),那么该点在空地上,否则就在圆塔上。
TEXT 8 (求1!+2!+...+n!)
输入一个正整数n,求1!+2!+...+n!的合。
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int j = 0;
int sum = 0;
for (i = 1; i <= n; i++)
{
int ret = 1;//每次重置ret=1
for (j = 1; j <= i; j++)
{
ret *= j;
}
sum += ret;
}
printf("%d\n", sum);
return 0;
}
对于求1!+2!+...+n!,首先要会求n!是多少。
//求n!
#include<stdio.h>
int n = 0;
int j = 0;
int ret = 1;
scanf("%d",&n);
for (j = 1; j <= n; j++)
{
ret *= j;
}
上述部分代码为求n!的阶乘,再将其放到for循环中,将每次阶乘的结果累加即可。
这里注意,ret为每次求n的阶乘时的计数变量,当求完该阶乘时,在求下一个数的阶乘之前要将其重置为1,否则ret会保留历史数据,导致结果越来越大。
TEXT 9 (求完数)
一个数如果等于它的因子之和,这个数就被称为完数。
例如:6的因子为1、2、3,1+2+3=6,所以6是完数。(因子就是所有可以整除这个数的数,但不包括这个数的自身)
求1000以内的所有完数,并按如下格式输出:
6是完数,它的因子是:1 2 3
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
for (i = 1; i < 1000; i++)
{
int sum = 0;
int k = 0;
int arr[50] = { 0 };//存放因子
for (j = 1; j < i; j++)//判断完数部分
{
if (i % j == 0)
{
sum += j;
arr[k++] = j;//后置++,先使用,再++
}
}
if (sum == i)
{
printf("%d是完数,它的因子是:", i);
for(k=0;arr[k]!='\0';k++)//遍历打印因子
{
printf("%d ", arr[k]);
}
putchar('\n');
}
}
}
创建一个arr的数组来将因子存放起来,因为要求1000以内的完数,所以这里arr的空间不能太小,要留出足够大的空间来存放因子。用两个for循环进行完数的判断,然后将完数的因子遍历打印出来即可。
TEXT 10(求水仙花数(迭代和递归))
求所有的水仙花数,水仙花数是一个三位数,各位数字的立方和等于其本身。
例如:,故153是水仙花数。
迭代方法:
#include<stdio.h>
#include<math.h>
int main()
{
int i = 0;
int j = 0;
for (i = 100; i < 1000; i++)
{
int ret = i;
int sum = 0;
for(j = 1; j <= 3; j++)//求各位数的立方和
{
sum += (int)pow((ret%10), 3);//(int)为强制类型转换
ret = ret / 10;
}
if (sum == i)//立方和等于其本身,便是水仙花数
{
printf("%d是水仙花数\n", i);//153 370 371 407
}
}
return 0;
}
因为水仙花数是三位数,所以在大循环中,i的范围设定为100 <= i < 1000。
然后开始每次求i的各位数的立方和:为了不改变i的值,创建一个ret变量,将i值赋给ret,每次循环结束后,将会赋予ret新的i值。
这里的思想与TEXT 6的逆序打印有些类似,每次找到最后一位数,求其立方和,用sum记录下来,记录完后将ret/10。第一次循环找到个位数的立方和,第二次循环找到十位数的立方和,第三次循环找到百位数的立方和,因为i为三位数,所以只需要循环三次即可。
sum += (int)pow((ret%10), 3),这里(int)为强制类型转换,将pow的double类型返回值转换为整型,让sum接收。(当然,即使不转换在VS编译器中也能成功运行)
通过上述代码可以观察到,在整个函数中,我们创建了两个局部变量来存放我们过程中的结果,整个代码写的非常冗杂,利用递归的方法可以简化我们的代码。
递归方法:
#include<stdio.h>
#include<math.h>
int flo(int i)
{
int sum = 0;
if (i / 10 != 0)
{
sum = flo(i / 10);
}
return sum += pow((i % 10), 3);
}
int main()
{
int i = 0;
for (i = 100; i < 1000; i++)
{
if (flo(i) == i)
{
printf("%d是水仙花数\n", i);
}
}
return 0;
}
递归的思想稍微有些抽象,这里用图展示更好理解一些。
例如:求125各位的立方
- 首先,125可以拆分为12和5,求5的立方+求12各位的立方
- 其次,12可以拆分为2和5,求2的立方+求1的各位的立方
- 最后,1就它自己,求1的立方。
下面为递归调用时的流程图:
return sum += pow((i % 10), 3);可以理解为:
1、sum += pow((i % 10), 3);
2、return sum;
递归:就是利用函数自己调用自己,从而实现化繁为简,大事化小。
递归主要分为递、和归两部分,先递再归。
每次递归时,要越来越接近if表达式中的界限,若是没有界限,那么将无限递归,陷入死循环。
例如125递归时,当1/10=0时,表达式为假,便不再调用函数,开始进行下一条语句,计算sum的值,然后return到上一个递归中,直到全部return完,递归结束。