《妙趣横生的算法》(C语言实现)-第5章 数学趣题(一)
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- [《妙趣横生的算法》(C语言实现)-第5章 数学趣题(一)](#《妙趣横生的算法》(C语言实现)-第5章 数学趣题(一))
- 前言
- [5.1 舍罕王的失算](#5.1 舍罕王的失算)
- [5.2 求两个数的最大公约数和最小公倍数](#5.2 求两个数的最大公约数和最小公倍数)
- [5.3 哥德巴赫猜想的近似证明](#5.3 哥德巴赫猜想的近似证明)
- [5.4 三色球问题](#5.4 三色球问题)
- [5.5 百钱买百鸡问题](#5.5 百钱买百鸡问题)
- [5.6 判断回文数字](#5.6 判断回文数字)
- [5.7 填数字游戏求解](#5.7 填数字游戏求解)
- [5.8 新郎和新娘](#5.8 新郎和新娘)
- [5.9 爱因斯坦的阶梯问题](#5.9 爱因斯坦的阶梯问题)
- [5.10 寻找水仙花数](#5.10 寻找水仙花数)
- [5.11 猴子吃桃问题](#5.11 猴子吃桃问题)
- [5.12 兔子产仔问题](#5.12 兔子产仔问题)
- [5.13 分解质因数](#5.13 分解质因数)
- [5.14 常胜将军](#5.14 常胜将军)
- [5.15 求圆周率的近似值](#5.15 求圆周率的近似值)
- [5.16 魔幻方阵](#5.16 魔幻方阵)
- [5.19 完全数](#5.19 完全数)
- [5.20 亲密数](#5.20 亲密数)
- 总结
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
5.1 舍罕王的失算
【题目要求】
舍罕是古印度的国王,据说他十分好玩,宰相达依尔为讨好国王,发明了现今的国际象棋献给国王。舍罕非常喜欢这项游戏,于是决定嘉奖达依尔,许诺可以满足达依尔提出的任何要求。达依尔指着舍罕王前面的棋盘提出了要求:"陛下,请您按棋盘的格子赏赐我一点麦子吧,第1个小格赏我一粒麦子,第2个小格赏我两粒,第3个小格赏我四粒,以后每一个小格都比前一个小格赏的麦粒数增加一倍,只要把棋盘上全部64个小格按这样的方法得到的麦粒都赏赐给我,我就心满意足了。"舍罕王听了达依尔这个"小小"的要求,想都没想就满口答应下来。结果在给达依尔麦子时舍罕惊奇地发现它要给达依尔的麦子比自己想象的要多得多,于是他进行了计算,结果令他大惊失色。问题是:舍罕王的计算结果是多少粒麦子?
【实现代码】
c
// 舍罕王的失算
# include <stdio.h>
int main()
{
unsigned long long int s = 0, p = 1; // 变量s记录赏赐的总的麦粒数,变量p记录第i个小格赏的麦粒数
for (int i = 1; i <= 64; ++i) { // 共有64个格子,使用for循环
s += p; // 累加求和
p *= 2; // 每一小格都比前一个小格赏的麦粒数增加一倍
}
printf("%llu", s); // 输出结果
return 0;
}
// 运行结果:18446744073709551615
【总结】
数据范围很大,使用unsigned long long int类型可满足要求。
另外,想清楚循环了多少次。
5.2 求两个数的最大公约数和最小公倍数
【题目要求】
编写一个程序计算两个正整数的最大公约数和最小公倍数。
【实现代码】
c
// 计算两个正整数的最大公约数和最小公倍数
# include <stdio.h>
int main()
{
int a, b; // 声明变量记录两个正整数
printf("Please input two numbers:");
scanf("%d%d", & a, & b); // 输出两个正整数
for (int i = (a <= b ? a : b); i > 0; --i) { // 计算最大公约数
if (a % i == 0 && b % i == 0) {
printf("the greatest common division of %d and %d is %d\n", a, b, i);
break;
}
}
for (int i = (a >= b ? a : b); ; ++i) { // 计算最小公倍数
if (i % a == 0 && i % b == 0) {
printf("the least common multiple of %d and %d is %d\n", a, b, i);
break;
}
}
return 0;
}
【总结】
可直接利用for循环解决问题,不过有些费时。欧几里得算法应该会快一些吧。
5.3 哥德巴赫猜想的近似证明
【题目要求】
所谓哥德巴赫猜想是说任何一个大于2的偶数都能表示成为两个素数之和。应用计算机工具可以很快地在一定范围内验证哥德巴赫猜想的正确性。请编写一个C程序,验证指定范围内哥德巴赫猜想的正确性,也就是近似证明哥德巴赫猜想(因为不可能用计算机穷举出所有正偶数)。
【实现代码】
c
// 哥德巴赫猜想的近似证明
// 验证1-100中大于2的偶数是否都能表示为两个素数之和
# include <stdio.h>
# include <math.h>
int isprime(int n) // 判断素数
{
int res = 1;
if (n == 1) { // 1不是素数
res = 0;
}
for (int i = 2; n > 2 && i <= sqrt(n); ++i) { // 2是素数
if (n % i == 0) { // 有除1和本身之外的因子的数也不是素数
res = 0;
break;
}
}
return res;
}
int main()
{
int k = 0;
for (int i = 1; i <= 100; ++i) { // 遍历1-100这100个数
if (i <= 2 || i % 2) { // 小于2或者是奇数要排除掉
continue;
}
for (int j = 2; j <= i - 2; ++j) {
if (isprime(j) && isprime(i - j)) {
printf("%2d = %2d + %2d", i, j, i - j);
++k; // 变量k用来控制输出格式
if (k == 5) {
printf("\n");
k = 0;
} else {
printf("\t");
}
break;
}
}
}
return 0;
}
【总结】
复习了判断素数的函数。
5.4 三色球问题
【题目要求】
有红、黄、绿三种颜色的球,其中红球3个,黄球3个,绿球6个。现将这12个球混放在一个盒子中,从中任意摸出8个球,编程计算摸出球的各种颜色搭配。
【实现代码】
c
// 三色球问题
# include <stdio.h>
int main()
{
for (int i = 0; i <= 3; ++i) { // 红球有3个,那么有4种可能性被拿出来
for (int j = 0; j <= 3; ++j) { // 黄球有3个,那么有4种可能性被拿出来
for (int k = 0; k <= 6; ++k) { // 绿球有6个,那么有7种可能性被拿出来
if (i + j + k == 8) { // 约束条件:任意拿出8个球
for (int r = 0; r < i; ++r) { // 输出结果
printf("red ");
}
for (int r = 0; r < j; ++r) {
printf("yellow ");
}
for (int r = 0; r < k; ++r) {
printf("green ");
}
printf("\n");
}
}
}
}
return 0;
}
【总结】
穷举法解决问题。
5.5 百钱买百鸡问题
【题目要求】
我国古代数学家张丘建在《算经》一书中曾提出过著名的"百钱买百鸡"问题。该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?请编写C程序,解决"百钱买百鸡"问题。
【实现代码】
c
// 百钱买百鸡问题
# include <stdio.h>
int main()
{
int a, b, c; // 三个变量分别表示公鸡、母鸡、小鸡的数目
for (int a = 0; a <= 100 / 5; ++a) { // 100元最多买100 / 5 = 20只公鸡
for (int b = 0; b <= 100 / 3; ++b) { // 100元最多买100 / 3 = 33只母鸡
for (int c = 0; c <= 300; ++c) { // 100元最多买100 * 3 = 300只小鸡
if (c % 3 == 0 && a + b + c == 100 && 5 * a + 3 * b + c / 3 == 100) { // 判断是否花了100元买了100只鸡,小鸡的数目要是3的倍数
printf("a = %d, b = %d, c = %d\n", a, b, c);
}
}
}
}
return 0;
}
【总结】
穷举法解决问题。
5.6 判断回文数字
【题目要求】
有这样一类数字,它们顺着看和倒着看是相同的数,例如121、656、2332等,这样的数字叫做回文数字。编写一个程序,判断从键盘接收的数字是否为回文数字。
【实现代码】
c
// 判断回文数字
# include <stdio.h>
int main()
{
int num;
printf("please input a number:");
scanf("%d", & num); // 输入正整数
int tmp = num, s = 0;
while (tmp) { // 计算逆序数
s = s * 10 + tmp % 10;
tmp /= 10;
}
if (s == num) { // 逆序数等于数字本身,那就是回文数字
printf("%d is a palindrome figures\n", num);
} else {
printf("%d is not a palindrome figures\n", num);
}
return 0;
}
【总结】
回文数字、回文字符串一类题型,清楚回文的含义。
5.7 填数字游戏求解
【题目要求】
有这样一个算式:ABCD * E = DCBA,其中ABCDE代表的数字各不相同。编写一个程序,计算出ABCDE各代表什么数字。
【实现代码】
c
// 填数字游戏求解
# include <stdio.h>
int main()
{
for (int a = 1; a < 10; ++a) {
for (int b = 0; b < 10; ++b) {
if (b == a) {
continue;
}
for (int c = 0; c < 10; ++c) {
if (c == b || c == a) {
continue;
}
for (int d = 1; d < 10; ++d) {
if (d == a || d == b || d == c) {
continue;
}
for (int e = 1; e < 10; ++e) {
if (e == a || e == b || e == c || e == d) {
continue;
}
int tmp = (a*1000 + b*100 + c*10 + d) * e;
if (tmp%10 == a && tmp%100/10 == b && tmp%1000/100==c && tmp/1000 == d) {
printf("A = %d, B = %d, C = %d, D = %d, E = %d\n", a, b, c, d, e);
printf("%d%d%d%d\n", a, b, c, d);
printf("* %d\n", e);
printf("----\n");
printf("%d%d%d%d", d, c, b, a);
return 0;
}
}
}
}
}
}
return 0;
}
【总结】
仔细观察可发现DCBA是ABCD的逆序数,可以用回文解决问题。
5.8 新郎和新娘
【题目要求】
3对新婚夫妇参加婚礼,3个新郎为A、B、C,3个新娘为X、Y、Z。有人不知道谁和谁结婚,于是询问了6位新人中的3位,但听到的回答是这样的:A说他将和X结婚;X说她的未婚夫是C;C说他将和Z结婚。这人听后知道他们在开玩笑,全是假话。请编程找出谁将和谁结婚。
【实现代码】
c
// 新郎和新娘
# include <stdio.h>
// 根据题目的叙述筛选除符合要求的答案
int match (int i, int j, int k, char wife[])
{
if (wife[i] == 'X') { // A不和X结婚
return 0;
}
if (wife[k] == 'X') { // X不和C结婚
return 0;
}
if (wife[k] == 'Z') { // C不和Z结婚
return 0;
}
return 1;
}
int main()
{
char husband[3] = {'A', 'B', 'C'};
char wife[3] = {'X', 'Y', 'Z'};
for (int i = 0; i < 3; ++i) { // 新郎A
for (int j = 0; j < 3; ++j) { // 新郎B
if (j == i) { // 不能1个新娘与2个新郎配对
continue;
}
for (int k = 0; k < 3; ++k) { // 新郎C
if (k == i || k == j) { // 不能1个新娘与2个新郎配对
continue;
}
// 三重循环,可以得到3*2*1 = 6种配对方案
// 根据题目的叙述筛选除符合要求的答案
if (match(i, j, k, wife)) { // 得到一种配对方式
printf("husband wife\n");
printf("A------%c\n", wife[i]);
printf("B------%c\n", wife[j]);
printf("C------%c\n", wife[k]);
}
}
}
}
return 0;
}
【总结】
不知道怎么把约束条件写出来诶,如何使用约束条件用程序写出来。
5.9 爱因斯坦的阶梯问题
【题目要求】
爱因斯坦曾出过这样一道有趣的数学题:有一个长阶梯,若每步上2阶,最后剩1阶;若每步上3阶,最后剩2阶;若每步上5阶,最后剩4阶;若每步上6阶,最后剩5阶;只有每步上7阶,最后刚好一阶也不剩。请问该阶梯至少有多少阶?编写一个C程序解决该问题。
【实现代码】
c
// 爱因斯坦的阶梯问题
# include <stdio.h>
int main()
{
for (int i = 1; ; ++i) {
if (i % 2 == 1 && i % 3 == 2 && i % 5 == 4 && i % 6 == 5 && i % 7 == 0) {
printf("该阶梯至少有%d阶\n");
break;
}
}
return 0;
}
// 运行结果:119
【总结】
穷举法。
5.10 寻找水仙花数
【题目要求】
如果一个3位数等于其各位数字的立方和,则称这个数为水仙花数。例如:407=44 4+00 0+777,因此407就是一个水仙花数。编写一个程序,找出全部的水仙花数。
【实现代码】
c
// 寻找水仙花数
# include <stdio.h>
int main()
{
for (int i = 100; i < 1000; ++i) { // 三位数
int a = i / 100; // 百位
int b = i / 10 % 10; // 十位
int c = i % 10; // 个位
if (i == a*a*a + b*b*b + c*c*c) { // 是水仙花数要输出
printf("%d\n", i);
}
}
return 0;
}
【总结】
穷举法。
5.11 猴子吃桃问题
【题目要求】
有一只猴子第一天摘下若干个桃子,当即吃掉了一半,又多吃了一个;第二天又将剩下的桃子吃掉了一半,又多吃了一个;按照这样的吃法每天都吃前一天剩下的桃子的一半又一个。到了第十天,就只剩下一个桃子了。问题:这只猴子第一天摘了多少个桃子。
【实现代码】
c
// 猴子吃桃问题
# include <stdio.h>
int main()
{
int s = 1; // 第十天只剩下一个桃子
for (int i = 0; i < 9; ++i) { // 前九天计算桃子数量
s = 2 * (s + 1);
}
printf("这只猴子第一天摘了%d个桃子。", s); // 输出结果
return 0;
}
// 这只猴子第一天摘了1534个桃子。
【总结】
递推。
5.12 兔子产仔问题
【题目要求】
13世纪意大利数学家斐波那契他的《算盘书》中提出这样一个问题:有人想知道一年内一对兔子可繁殖成多少对,便筑了一道围墙把一对新生的兔子关在里面。已知一对两个月大的兔子以后每一个月都可以生一对小兔子,而一对新生的兔子出生两个月后才可以生小兔子(例如:1月份出生,3月份才可产仔)。假如一年内没有发生死亡,则一年内共能繁殖成多少对?
【实现代码】
c
// 兔子产仔问题
# include <stdio.h>
int main()
{
int a = 1, b = 1, s = 0; // 第一月和第二月只有1对兔子
for (int i = 3; i <= 12; ++i) {
s = b + a; // 从第三月起,每月的兔子数量是前两个月的兔子数量之和
a = b; // 前一个月的兔子数量
b = s; // 前两个月的兔子数量
}
printf("一年内一对兔子可繁殖成%d对。", s); // 输出
return 0;
}
// 144
【总结】
递推。求第12个月的兔子数量,不是累加每个月的兔子数量哦。
5.13 分解质因数
【题目要求】
根据数论的知识可知任何一个合数都可以写成几个质数相乘的形式,这几个质数都叫做这个合数的质因数。例如24=222*3。把一个合数写成几个质数相乘的形式表示,叫做分解质因数。对于一个质数,它的质因数可定义为它本身。编写一个程序实现分解质因数。
【实现代码】
c
// 分解质因数
# include <stdio.h>
# include <math.h>
int isprime(int n)
{
int res = 1;
if (n <= 1) {
res = 0;
}
for (int i = 2; n > 2 && i <= sqrt(n); ++i) {
if (n % i == 0) {
res = 0;
break;
}
}
return res;
}
int main()
{
int num;
printf("Please input a number:");
scanf("%d", & num);
printf("%d = ", num);
int k = 0;
if (isprime(num)) { // 素数直接输出
printf("%d\n", num);
} else { // 合数进行分解
for (int i = 2; ; ++i) {
if (isprime(i) && num % i == 0) {
++k;
if (k > 1) {
printf("*");
}
printf("%d", i);
num /= i;
i = 1; // 下次循环依然从2开始判断是不是质因数
if (num == 1) {
break;
}
}
}
}
return 0;
}
【总结】
判断素数函数要清楚。
5.14 常胜将军
【题目要求】
现有21根火柴,两人轮流取,每人每次可以取走1至4根,不可多取,也不能不取,谁取最后一根火柴谁输。请编写一个程序进行人机对弈,要求人先取,计算机后取;计算机一方为"常胜将军"。
【实现代码】
c
// 常胜将军
# include <stdio.h>
int main()
{
int computer, people, spare = 21;
printf("--------------------------------\n");
printf("---- 你不能战胜我,不信试试 ----\n");
printf("Game begin:\n\n");
while (1)
{
printf("---- 目前还有火柴 %d 根 ----\n", spare);
printf("People:");
scanf("%d", & people);
if (people < 1 || people > 4 || people > spare) {
printf("你违规了,你取的火柴数有问题!\n\n");
continue;
}
spare -= people;
if (spare == 0) {
printf("\nComputer win! Game Over!\n");
break;
}
computer = 5 - people;
spare -= computer;
printf("Computer:%d\n", computer);
if (spare == 0) {
printf("\nPeople win! Game Over!\n");
break;
}
}
return 0;
}
【总结】
没有想法!怎么实现这个程序啊??
21根火柴,在人先取,计算机后取,每次取1-4根的前提下,只要保证每一轮的抽取(人先取一次,计算机再取一次)人抽到的火柴数与计算机抽到的火柴数之和为5就可以实现计算机的常胜不败。
5.15 求圆周率的近似值
【题目要求】
编写一个C程序,用来求出圆周率的近似值。
【实现代码】
c
// 计算圆周率的近似值
# include <stdio.h>
# include <math.h>
double getPI(int n);
int main()
{
int n;
double PI;
printf("Please enter accuracy\n");
scanf("%d", & n);
PI = getPI(n);
printf("The similar value of PI is \n%f\n", PI);
return 0;
}
double getPI(int n)
{
int div, i = 4;
double b = sqrt(2) / 2.0;
double c = 0.0;
for (div = 0; div < n; ++div) {
b = sqrt(2.0 - 2.0 * sqrt(1.0 - b * b)) * 0.5;
i *= 2;
}
c = b * i;
return c;
}
【总结】
计算圆周率的方法有许多,比如正多边形逼近、应用数值概率算法。
5.16 魔幻方阵
【题目要求】
所谓魔幻方阵是指在nn的矩阵中填写1-nn这些数字,使得它的每一行、每一列、以及两个对角线之和均相等。编写程序,打印出一种三阶的魔幻方阵。
【实现代码】
c
// 魔幻方阵
# include <stdio.h>
int main()
{
for (int a1 = 1; a1 < 10; ++a1) {
for (int a2 = 1; a2 < 10; ++a2) {
if (a1 == a2) {
continue;
}
for (int a3 = 1; a3 < 10; ++a3) {
if (a3 == a2 || a3 == a1) {
continue;
}
for (int a4 = 1; a4 < 10; ++a4) {
if (a4 == a3 || a4 == a2 || a4 == a1) {
continue;
}
for (int a5 = 1; a5 < 10; ++a5) {
if (a5 == a4 || a5 == a3 || a5 == a2 || a5 == a1) {
continue;
}
for (int a6 = 1; a6 < 10; ++a6) {
if (a6 == a5 || a6 == a4 || a6 == a3 || a6 == a2 || a6 == a1) {
continue;
}
for (int a7 = 1; a7 < 10; ++a7) {
if (a7 == a6 || a7 == a5 || a7 == a4 || a7 == a3 || a7 == a2 || a7 == a1) {
continue;
}
for (int a8 = 1; a8 < 10; ++a8) {
if (a8 == a7 || a8 == a6 || a8 == a5 || a8 == a4 || a8 == a3 || a8 == a2 || a8 == a1) {
continue;
}
for (int a9 = 1; a9 < 10; ++a9) {
if (a9 == a8 || a9 == a7 || a9 == a6 || a9 == a5 || a9 == a4 || a9 == a3 || a9 == a2 || a9 == a1) {
continue;
}
int r1 = a1 + a2 + a3;
int r2 = a4 + a5 + a6;
if (r1 != r2) {
continue;
}
int r3 = a7 + a8 + a9;
if (r3 != r2) {
continue;
}
int c1 = a1 + a4 + a7;
if (c1 != r3) {
continue;
}
int c2 = a2 + a5 + a8;
if (c2 != c1) {
continue;
}
int c3 = a3 + a6 + a9;
if (c3 != c2) {
continue;
}
int s1 = a1 + a5 + a9;
if (s1 != c3) {
continue;
}
int s2 = a3 + a5 + a7;
if (s2 != s1) {
continue;
}
printf("%d %d %d\n", a1, a2, a3);
printf("%d %d %d\n", a4, a5, a6);
printf("%d %d %d\n", a7, a8, a9);
return 0;
}
}
}
}
}
}
}
}
}
return 0;
}
【总结】
耐心一些,认真一些!
5.19 完全数
【题目要求】
如果一个数恰好等于它的因子之和,那么这个数就被称为完全数。例如6的因子为1,2,3,而6 = 1+2+3,因此6是一个完全数。求出1000以内的完全数。
【实现代码】
c
// 完全数
# include <stdio.h>
int main()
{
for (int i = 1; i <= 1000; ++i) { // 1000以内的数字
int tmp = 0;
for (int j = 1; j < i; ++j) {
if (i % j == 0) {
tmp += j; // 对因子累加求和
}
}
if (tmp == i) {
printf("%d ", i);
}
}
return 0;
}
【总结】
对数字的因子累加求和。
5.20 亲密数
【题目要求】
如果整数A的全部因子(包括1,不包括A本身)之和等于B,并且整数B的全部因子(包括1,不包括B本身)之和等于A,则称整数A和B为亲密数。求解3000以内的全部亲密数。
【实现代码】
c
// 亲密数
# include <stdio.h>
int main()
{
for (int a = 2; a <= 3000; ++a) {
int b = 0;
for (int i = 1; i < a; ++i) {
if (a % i == 0) {
b += i;
}
}
int s = 0;
for (int i = 1; i < b; ++i) {
if (b % i == 0) {
s += i;
}
}
if (s == a && a < b) {
printf("%d %d\n", a, b);
}
}
return 0;
}
【总结】
对数字的因子累加求和。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。