由100盏灯想到的(一)

原题目地址:http://www.cnblogs.com/DeanChopper/p/4772593.html

  大厅里有100盏灯,每盏灯都编了号码,分别为1-100。每盏灯由一个开关来控制。(开关按一下,灯亮,再按一下灯灭。开关的编号与被控制的灯相同。)开始时,灯是全灭的。现在按照以下规则按动开关。
第一次,将所有的灯点亮。
第二次,将所有2的倍数的开关按一下。
第三次,将所有3的倍数的开关按一下。
以此类推。第N次,将所有N的倍数的开关按一下。
问第100次按完以后,大厅里还有几盏灯是亮的。

网上找了一下,此题还有其他的表述方式类似:
  礼堂里有100盏电灯,编号1-100,每盏灯由一根灯绳控制,拉一下改变状态.开始灯全是灭的,100个同学依次进入礼堂,

第一个学生把1的倍数的灯绳拉一下,灯全亮;

接着第二个同学把2倍数的灯绳拉一下;

第三个同学把3倍数的灯绳拉一下······第100个学生把100的倍数的灯绳拉一下.最后,礼堂里哪些灯是亮的?

1,暴力解法:

暴力解法一般是思路上最接近题意的,按题目要求的步骤直接求解,暴力求解一般计算量也是最大的。

我一般都是先用笨办法计算出结果,再想办法优化。现给出C#暴力解法,得出最后的结果,代码如下:

 1     class Program {
 2
 3         //100盏灯,默认全是关着的
 4         static bool[] lights = new bool[100];
 5
 6         static void Main(string[] args) {
 7             //100次开关测试
 8             for (int i = 1; i <= 100; i++) {
 9                 ChangeState(i);
10             }
11
12             //开关完成,打印最后的结果
13             Console.WriteLine("最后亮灯的还有{0}盏。", lights.Count(r => r));
14
15             //分别打印每盏灯
16             for (int i = 0; i < 100; i++) {
17                 if (lights[i]) {
18                     Console.WriteLine(i + 1);
19                 }
20             }
21
22             Console.WriteLine("实验结束!");
23             Console.ReadKey();
24         }
25
26         /// <summary>
27         /// 开关灯
28         /// </summary>
29         /// <param name="x"></param>
30         private static void ChangeState(int x) {
31
32             for (int i = 0; i < 100; i++) {
33                 if ((i + 1) % x == 0) {
34                     lights[i] = !lights[i];
35                 }
36             }
37
38         }
39
40     }

上面的解法很容易就能求出结果,各位可以先自行测试一下。

2.优化

  暴力解法可以得到结果,但这肯定是不能让人满意的。现在回过头来再分析这个题。

第一次操作,每个灯的开关都被按一次;

第二次操作,2的倍数的开关都被按一次;

.....

下面列出前十次,前十个数的具体情况

  灯1 灯2 灯3 灯4 灯5 灯6 灯7 灯8 灯9 灯10
步骤1 操作 操作 操作 操作 操作 操作 操作 操作 操作 操作
步骤2   操作   操作   操作   操作   操作
步骤3     操作     操作     操作  
步骤4       操作       操作    
步骤5         操作         操作
步骤6           操作        
步骤7             操作      
步骤8               操作    
步骤9                 操作  
步骤10                   操作
操作次数 1 2 2 3 2 4 2 4 3 4

可以看到,最下面一列是操作的次数,操作次数为奇数次的,灯最后是打开的状态,是偶数次,则为关闭。

被操作的规律如下:

灯1:1

灯2:1,2

灯3:1,3

灯4:1,2,4

...

依次写下去,就可以发现,每个灯被操作的步骤,其实为此灯编号的因数。

如灯36被操作的步骤:1,2,3,4,6,9,12,18,36

此时题目转化为求[1-100]100个数中,因数个数为奇数的数的数量是多少。

因为最近在学习Python,求因数的算法用python 语言给出,3.4 版本运行成功 如下:

 1 def getZYS(n):
 2     x=2
 3     zys=[]
 4     zys.extend([1,n])
 5     while x*x<=n:
 6         if n%x==0:
 7             if x*x==n:
 8                 zys.extend([x])
 9             else:
10                 zys.extend([x,n//x])
11         x+=1
12     return zys
13
14 n=input(‘请输入一个正整数:‘)
15 n=int(n)
16 lb=getZYS(n)
17 lb=sorted(lb)
18 print(lb)
19             

此时,题目的解法已经第一次被推广,在一定程度上,我们已经可以解决更多类似的问题。推广后的解法请自行试着去解决。

3.就事论事

求一个正整数的质数的过程,如上面代码所示,其实就是对某个数平方根以下的数试着求余,但具体到本题而言,转化一下描述为,怎样快速判断一个数的因数个数是否为奇数。

请看上面的代码,第7-10行,如果能深刻理解这几行,上面所述的题目会有更快的解法。

我们注意到,求一个数因数的过程,是从1开始到其平方根,除平方根外,其他的因数都是成对的出现!,也就是,只有平方数的因数是奇数个!,100以内的平方数只有10个,分别是1,4,9,16,25,36,49,64,81,100,所以上述题目的最后结果是10个灯最后是亮着的。

优化完的代码,注释要多一些,代码本身将非常之少,因为100的平方根是10,所以最后亮10盏灯。

你明白了没有?

附:

求一个正整数的因数的个数的研究,最初来源于一个Python群的入群题目:

求1<=i<=10**12范围内所有d(i)的和的末12位,d(i)表示i的正约数的和,i为整数

这个题目可以试着解一下

未完待续)

时间: 2024-10-10 23:17:33

由100盏灯想到的(一)的相关文章

由100盏灯想到的(二)

本系列的第一篇: http://www.cnblogs.com/dhf327/p/4773672.html 100盏灯的问题,上次我们算是基本解决了,不管算法上是否够优化,至少我们已经在可接受的时间得到了答案. 但是最后还留了一道题,亲们,你们是不是已经想出来了? 一,上次的题目 上一篇给出了python求一个正整数的所有的因数的方法,这个方法目前工作正常,求单个正整数的所有因数速度上也没有任何问题. 但是结合上一篇最后的题目,有心的同学一下子就看出问题来了,1到10的12次方,假设求每个数的所

100人100盏灯(详解)

题:一百盏灯排成一排,初始状态是亮的, 编号为 1-100,100个人编号1-100.每个人从1号灯开始逐次走过这100盏灯.每个人只拉他对应编号的倍数的灯,问最后亮着几盏灯? 这是一道很经典的笔试题.频繁出现.下面是比较简洁的实现代码.已验证. 1 package 笔试; 2 3 public class 完全平方数100人和灯 { 4 public static void main(String[] args) { 5 boolean[] light=new boolean[100]; 6

js:自动亮起100盏灯

1)    使用js在页面上显示100盏灯,并标记从1到100的编号2)    页面加载后3秒,从编号是1的灯依次自动亮起.3)    每过0.5秒亮下一盏灯(10分)4)    所有灯亮起后,弹出确认框,询问是否要关闭页面5)    点确定,页面自动关闭.点取消,页面不动. <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html

还有几盏灯?

大厅里有100盏灯,每盏灯都编了号码,分别为1-100.每盏灯由一个开关来控制.(开关按一下,灯亮,再按一下灯灭.开关的编号与被控制的灯相同.)开始时,灯是全灭的.现在按照以下规则按动开关. 第一次,将所有的灯点亮. 第二次,将所有2的倍数的开关按一下. 第三次,将所有3的倍数的开关按一下. 以此类推.第N次,将所有N的倍数的开关按一下. 问第100次按完以后,大厅里还有几盏灯是亮的. 解答: 这题和数字的因数个数有关.例如:12=1*12=2*6=3*4,所以1,2,3,4,6,12就是12的

屋子里有1到100号100盏关闭的灯

屋子里有1到100号100盏关闭的灯,门外有1到100号100个人,每个人都要进屋一次,把与自己序号对应的和是自己序号倍数的灯绳拉一下,(比如1号要拉所有的灯绳,2号要拉2,4,6的灯绳,而100号只需拉100号灯绳)问:当100人都出来后,屋子里亮着的灯有几盏? 这么说呢,大家都知道答案是 平方数 1,4,9...100 ok,首先要想到肯定是拉灯拉了奇数次的才能是打开的...想想如果编号为N,那么肯定是前面拉过N的i必定能整除N,所以肯定i是N的因数...所以题目转换为求N,N的因数的个数是

现在有100个标记过的电灯泡。第一个人经过这些灯时,点亮所有的灯,第二个人经过时每隔一盏灯就切换开关一次,第三个人经过时每隔两盏灯切换开关一次。请问,当第100个人经过时,还剩多少盏亮着的灯?

做了一个草图:10(纵10人)X10(横10栈灯) 第一个人:1 1 1 1 1 1 1 1 1 1第二个人:0 1 0 1 0 1 0 1 0 1第三个人:0 0 1 0 0 1 0 0 1 0第四个人:0 0 0 1 0 0 0 1 0 0第五个人:0 0 0 0 1 0 0 0 0 1第六个人:0 0 0 0 0 1 0 0 0 0第七个人:0 0 0 0 0 0 1 0 0 0第八个人:0 0 0 0 0 0 0 1 0 0第九个人:0 0 0 0 0 0 0 0 1 0第十个人:0 0

哪个开关控制哪盏灯

QUESTION: 房间里面有三盏灯,屋外有三个开关,分别控制着三盏灯,只有进入房间,才能看到哪盏灯是亮的.请问如何只进入房间一次,就能指明哪个开关控制哪盏灯??? ANSWER: 假设开关编号为A,B,C.打开开关A,但不进入房间:等过了大约若干分钟后,关闭开关A,并且打开开关B:同时迅速进入房间内,并且用手摸房间内不亮的两盏灯以确定哪盏灯发热.设[房间内亮着的灯.不亮但温度较高的灯.不亮但温度较低的灯]的编号分别为L1.L2.L3. 判断的结果是:开关A控制L2:开关B控制L1:开关C控制L

从150盏灯这道奥数题说起......

前段时间,成都9岁学生纠错奥赛名题这篇文章在网上爆红.本文不关注神童之类的新闻,仅仅从计算机实现的角度来验证题目正确性. 题目描述(需求描述): 150盏亮着的电灯,各有一个拉线开关控制,按顺序编号为1,2,3,-,150.将编号为3的倍数的灯的拉线各拉一下,再将编号为5的倍数的灯的拉线各拉一下,拉完后亮着的灯数为__盏. 使用暴力穷举法来获得正确答案: 为了简单期间,我们可以将150盏灯缩小10倍,变为15盏灯,这样就很容易用暴力穷举法来标记出灯的最终结果: 答案: 第一遍拉灭3的倍数,15÷

轻松学习JavaScript四:JS点击灯泡来点亮或熄灭这盏灯的网页特效映射出JS在HTML中作用

我们开始解释JS在HTML中作用.对于因特网和视窗操作系统,JavaScript都意味着未来. (1)JavaScript:写入HTML输出 实例代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://ww