一、自幂数
1、介绍
自幂数,也被称为阿姆斯特朗数,是一种特殊类型的数,在数学上具有一个有趣的性质:一个 n
位的正整数,其各个位上的数字的 n
次幂之和等于它本身。
这里是自幂数的定义步骤:
-
确定位数 (
n
) : 首先,要确定一个数是几位数。例如,153
是一个三位数,因此n = 3
。 -
计算每个位上的数字的
n
次幂 :接着,将该数的每个位上的数字取出来,分别计算其n
次幂。对于153
,计算如下:1
的三次幂是1
5
的三次幂是125
3
的三次幂是27
-
计算这些幂的和 :将上一步中得到的所有幂相加。对于
153
,其和是1 + 125 + 27 = 153
。 -
验证和是否等于原数 :如果这个总和等于原来的数,则称该数为自幂数。所以,
153
是一个自幂数,因为1^3 + 5^3 + 3^3 = 153
。
不同位数的自幂数有不同的名称:
- 三位数的自幂数 :这些是最常见的自幂数,通常被称为水仙花数。除了前面提到的
153
,还包括370
、371
和407
。 - 四位数的自幂数 :例如
1634
,因为1^4 + 6^4 + 3^4 + 4^4 = 1634
。 - 五位数的自幂数 :例如
54748
,因为5^5 + 4^5 + 7^5 + 4^5 + 8^5 = 54748
。 - 依此类推,你可以找到更多位数的自幂数。
自幂数不仅局限于三位数,但随着位数的增加,自幂数也变得越来越稀少。自幂数是数学中的一个奇特现象,通常用于编程练习和算术游戏中。在数学理论中,除了被当作一种趣题外,并没有特别的意义。
我们常说的水仙花数就是三位的自幂数。
2、例子
打印0~100000内的自幂数:
cpp
#include <stdio.h>
#include <math.h>
int CountDigit(int x)//判断数字的位数
{
int counter = 0;
while (x)
{
x /= 10;
counter++;
}
return counter;
}
int main()
{
int i = 0,j = 0,s = 0,num = 0;
for (i = 0; i <= 100000; i++)
{
num = i;
int digits = CountDigit(i);
for(s = 0,j = 0;j < digits;j++)
{
s += (int)pow(num % 10, digits);
num /= 10;
}
if (s == i)
{
printf("%d ", i);
}
}
return 0;
}
运行结果:
代码分析:
-
CountDigit 函数 :这个函数的目的是确定一个给定的整数
x
有多少位。它通过一个while
循环实现:只要x
不为0,就将x
除以10,并将计数器counter
加1。循环结束时,counter
就是x
的位数。 -
main 函数:
- 初始化了四个整型变量
i
,j
,s
,num
。i
将作为循环变量,j
将在内部循环中使用,s
用于累加幂的和,num
存储i
的临时副本,防止i
的值在内部循环中被改变。 - 外层
for
循环:for (i = 0; i <= 100000; i++)
,它将从0迭代到100000,检查每个数是否是自幂数。 - 在每次外层循环的迭代开始时,先将
i
的值赋给num
,然后调用CountDigit(i)
函数得到当前i
的位数,这个值存储在digits
变量中,以便在后续计算中使用。 - 内层
for
循环:for (s = 0, j = 0; j < digits; j++)
,用于计算i
的每一位上的数字的digits
次幂之和。每次循环:num % 10
提取num
的最后一位数字。pow(num % 10, digits)
计算这个数字的digits
次幂。s += ...
将这个幂加到s
上,s
是一个累加器,用来计算所有幂的和。num /= 10
通过整数除法去除num
的最后一位数字。
- 当内层循环结束时,如果
s
(幂的和)等于原始的数i
,则表明找到了一个自幂数,printf
函数将其打印出来。
- 初始化了四个整型变量
整个程序的执行流程就是对从0到100000的每个整数检查是否为自幂数,并打印出这个范围内所有的自幂数。
二、打印菱形
编写一个程序用来打印菱形:
cpp
#include <stdio.h>
int main()
{
int i = 0, j = 0,n = 0;
scanf("%d", &n);//n应当为奇数
for (i = 0; i < (n / 2) + 1; i++)
{
for (j = 0; j < (n / 2) - i; j++)
{
printf(" ");
}
for (j = 0; j < 2 * (i + 1) - 1; j++)
{
printf("*");
}
printf("\n");
}
for (i = 0; i < n / 2; i++)
{
for (j = 0; j < i + 1; j++)
{
printf(" ");
}
for (j = 0; j < n - 2 * (i + 1); j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
程序的工作流程如下所述:
-
用户输入 :程序首先提示用户输入一个整数
n
,该值应该是奇数。 -
打印菱形的上半部:
- 外层
for
循环从i = 0
迭代到i < (n / 2) + 1
。该循环负责打印菱形的上半部,包括最中间的一行。 - 内层第一个
for
循环打印前置空格。对于菱形的每一行,前置空格的数量是(n / 2) - i
,这样星号后面的空格会随着每一行递增的i
而递减。 - 内层第二个
for
循环打印星号。每行的星号数量是2 * (i + 1) - 1
,这保证了星号的数量随着每一行递增的i
而递增,每次增加两个星号(除了第一行)。 - 每一行打印完星号和前置空格后,
printf("\n")
打印一个换行符,以开始新的一行。
- 外层
-
打印菱形的下半部:
- 外层
for
循环从i = 0
迭代到i < n / 2
。该循环负责打印除了最中间的行以外的菱形下半部分。 - 内层第一个
for
循环打印前置空格。对于下半部分的每一行,前置空格的数量是i + 1
,这样随着下半部分每一行递增的i
,前置空格也在递增。 - 内层第二个
for
循环打印星号。每行的星号数量是n - 2 * (i + 1)
,这确保了星号的数量随着下半部分每一行递增的i
而递减,每次减少两个星号。 - 与上半部一样,每一行打印完星号和前置空格后,
printf("\n")
打印一个换行符,以开始新的一行。
- 外层
最终,当所有循环执行完成时,如果 n
是一个奇数,你将得到一个完整的菱形图案。
这里是一个例子的输出,如果用户输入的 n
是 5
:
三、买汽水
买汽水,一元一瓶,两个空瓶可以换一瓶汽水,20元可以喝几瓶。
1、循环
cpp
#include <stdio.h>
int main()
{
int money = 0;
scanf("%d", &money);
int totalBottles = money;
int emptyBottles = totalBottles;
while (emptyBottles >= 2)
{
int newBottles = emptyBottles / 2;
totalBottles += newBottles;
emptyBottles = emptyBottles % 2 + newBottles;
}
printf("%d\n", totalBottles);
return 0;
}
程序分析:
- 用20元钱买20瓶汽水,所以初始的空瓶数量也是20。
- 当你有2个或更多的空瓶时,继续执行循环:
- 将空瓶数除以2得到新的汽水瓶数(因为2个空瓶可以换1瓶汽水)。
- 把新的汽水瓶数加到总瓶数上。
- 更新空瓶的数量,等于之前空瓶数除以2的余数加上新换得的汽水数量。
- 当你没有足够的空瓶换取汽水时,循环结束,此时 totalBottles 变量中存储的就是你能喝的汽水总数。
- 打印结果。
运行结果:
2、递归
cpp
#include <stdio.h>
int Func(int totalBottles, int emptyBottles)
{
if (emptyBottles < 2)
{
return totalBottles;
}
int newBottles = emptyBottles / 2;
return Func(totalBottles + newBottles, emptyBottles % 2 + newBottles);
}
int main()
{
int money = 0;
scanf("%d", &money);
printf("%d\n", Func(money, money));
return 0;
}
程序执行的流程大致如下:
-
程序启动后,进入
main
函数,这是每个C程序的入口点。 -
程序声明了一个整型变量
money
,用来存放用户通过标准输入提供的金额。 -
程序调用
scanf
函数等待用户输入一个整数,该整数代表用户用来购买汽水的金额。输入的整数将被保存在money
变量中。 -
输入完毕后,程序调用
Func
函数,将money
作为参数传入,这里有两个作用:一是表示初始时用这些钱可以直接买到的汽水数量,二是同样数量的空瓶可以开始进行换购。 -
Func
函数内部,首先检查当前的空瓶数量是否足够兑换更多的汽水。如果不足2个,则无法继续兑换,函数返回当前统计到的汽水总瓶数。 -
如果当前空瓶数量足够换更多汽水(即2个或2个以上),则计算能够兑换的新汽水瓶数,并更新空瓶数量(包括兑换后剩余的空瓶和新的空瓶)。
-
Func
利用递归调用自身,将更新后的汽水总数和空瓶数量作为新的参数,继续上述兑换过程。 -
当
emptyBottles
不再足以兑换新的汽水时,递归结束,Func
函数返回最终计算的汽水总瓶数。 -
main
函数接收到Func
函数返回的总瓶数后,通过printf
函数输出到控制台。 -
最后,
main
函数执行完毕,返回0,标志着程序的正常结束。
运行结果: