1. 亮灯问题:
现有100盏灯,编号1到100。每盏灯都有一个开关,开始时,100盏灯全部关闭。
做如下操作:
<1> . 第1次,按下所有编号是1 的倍数的灯的开关;
<2> . 第2次,按下所有编号是 2 的倍数的灯的开关;
<3> . 第3次,按下所有编号是 3 的倍数的灯的开关;
……………………
<n> . 第n次,按下所有编号是 n 的倍数的灯的开关;
…………………………
<100> . 第100次,按下所有编号是 100 的倍数的灯的开关。
问: 经过上述操作后, 总有几盏灯在亮, 他们的编号分别是???
分析: 每盏灯开始都是关着的,最后亮着的那盏的肯定是开关被按下了奇数次。
而对于每盏灯,都在什么时候灯的开关被按下呢?
显然有上述操作可见,该灯的编号是次数的倍数时该灯被的开关被按下。
反过来,也就是 次数是该灯编号的约数时,该灯的开关被按下。
上述,问题转化,为求灯编号的约数的个数的问题,
而亮灯问题转化为灯的编号的约数的个数为奇数的问题。
看到这里,我们学计算机的同学,都禁不住的,要通过编程解决该问题,
我开始也是这样想,也是这样做的。能不能多想一步,灵机一动,不用编程,就能解决呢?
先看一下,怎样通过编程,解决该问题? 更巧妙方法,稍后介绍。(也许编程都的结果,会对你有所启发^o^).(有点像启发式思维,有木有,,,)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int i;
int j;
int count; //统计约数的个数;
int n = 0; //统计亮灯的总数;
printf("亮灯的编号是:");
for(i = 1; i <= 100; ++i) {
count = 0;
for(j = 1; j<=i; ++j){
if(i % j == 0) ++count;
}
if(count % 2) {
printf("%d ", i);
++n;
}
}
printf("\n所有亮着的灯的个数是:%d", n);
return 0;
}
运算结果:
看到上述结果,如果你只打印亮灯的个数,也许你没有发现什么,但是亮灯的编号好像看起来有规律呀(是的有规律的)。
更巧妙的解决甚至不用动笔:
前面提到上述亮灯问题等价于求约数个数为奇数的灯的编号。
一个数的约数个数为奇数,这个数有什么特征呢?
我们知道,一个数的约数总是成对存在的。
而一个数的约数的个数为奇数,说明该数一个成对的约数等于同一个数。
即该数是一个数的平方,即该数是一个平方数。
上述问问题: 亮灯问题=》灯的编号的约数为奇数个=》该等的编号是一个平方数。
而 1到100中,平方数有 1^2 = 1, 2^2 = 4, 3^2 = 9, 4^2 = 16, 5^2 = 25,
6^2 = 36, 7^2= 49, 8^2 = 64 9^2 = 81, 10^2 = 100.
故,1到100中有10个平方数 ,亮灯的编号都是这些平方数。
(该题目出自,某不知名培训机构的测试题中)
2. 余数问题:
有这样一个三位数, 被5余4,被6除余5,被7除余6, 求这个三位数。
分析: <1>. 编程解决,计算机最擅长这个,穷举呗。
<2>. 是否有更好的方法。
编程方案:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int count = 0;
for(i = 0; i < 1000; ++i) {
if(i % 5== 4 && i % 6 == 5 && i % 7 == 6){
printf("%d, ", i);
++count;
}
}
printf("\n共有%d个。", count);
return 0;
}
计算机结果:
<2>更好方法:不妨令该数为n,有题设可知, n+1 能别 5, 6, 7 同时整除。
n+1 = 5 * 6 *7 *k; (k为整数)
且n+1 为一个三位数,则 100<=n+1 < 1000.
即 100< =210*k < 1000.
所以k= 1, 2, 3, 4, 对应的n为 209, 419, 629,839 。
如果不通过形式化的列举,往往会漏解。说的是三位数,而不是最小的三位数。
可见,形式化的重要性。将问题形式化,能够更好的解决问题。(学学抽象数学,还是哟必要的)。
(该题出现在某知名杀毒软件的笔试题中)。