开灯关灯问题

题目:

大厅里有100盏灯,每盏灯都编了号码,分别为1-100。每盏灯由一个开关来控制。(开关按一下,灯亮,再按一下灯灭。开关的编号与被控制的灯相同。)开始时,灯是全灭的。现在按照以下规则按动开关。

第一次,将所有的灯点亮。
第二次,将所有2的倍数的开关按一下。
第三次,将所有3的倍数的开关按一下。
以此类推。第N次,将所有N的倍数的开关按一下。

问第N次(N大于等于2,且小于等于100)按完以后,大厅里还有几盏灯是亮的。

思路:

1) 暴力破解  用一个数组代替灯  通过模拟按开关的操作  来实现

2) 通过题意  我们知道 每次按的 都是次数的 倍数  所以 我们可以通过求公约数来实现

3) 通过思路2  发现 其实 最后灯亮这的都是按了奇数次的灯。


下面是具体的解释和代码实现

为了便于程序的扩展性 lights 表示灯数   num 表示第几次。

 1)一共有100 盏灯。每一次 都把为次数的倍数灯的开关按一下。

对于这样的问题 最先想到的当能是暴力循环了。  用一个装有100 个元素的boolean 类型的数组 代表这100 盏灯。暴力循环 每按一次按钮 对应元素的值变换一次。 


public static void findLights(int lights,int num) {
		if (num <1) System.out.println("参数错误"); 
		else {
			// 用一个0~99 的boolean数组表示 第1到100 盏灯。
			boolean[] array = new boolean[lights];
			for (int i = 1; i <= num; i++) { // 第几次
				for (int j = i-1; j< array.length;j++) { // 因为j要为i的倍数 所以必须大于等于i-1;
					if ((j+1)%i ==0 ) { // j 应该表示的是第 j+1 盏灯
						array[j] = !array[j]; // 按下开关  取反
					}
				}
			}
			// 统计
			int count = 0;
			for (int i = 0; i< array.length;i++) {
				if(array[i]) count++;
			}
			System.out.println("最后亮了 " + count + " 盏灯!");
		}
		}

 2)按下次数的倍数的开关。 可以反过来理解为 当次数是灯的编号的约数的时候按下开关。例如: 编号为12 的灯 在 第1,2,3,4,,6,12次被按下而 

12=1*12=2*6=3*4一共按了6次  偶数次 所以最后是关着的   编号为9的等 在第1,3,9次被按下 一共按了奇数次 所以最后灯是开着的。


public static void findLights2(int lights,int num) {
		if (num <1) System.out.println("参数错误"); 
		else {
			// 求公约数个数  如果最后是奇数个  灯亮  偶数 灯灭
			int count = 0; // 公约数个数
			int total = 0; //总的亮灯数
			for (int i = 1; i <= lights;i++) {
				for (int j = 1; j<=i && j <= num;j++) { // 既然是约数 所以j得小于i.而j不能大于次数 num
					if (i%j==0) {// 是约数 按下的次数+1;
						count++;
					}
				}
			if (count%2!=0) total++;
			count = 0; // 下一盏灯 重新计算
			}
			System.out.println("最后亮了 " + total + " 盏灯!");	
		}
	}

3) 通过思路2我们知道了 最后亮灯的都是按了奇数次的灯。在求约数时  因为:N=a*b 有了a就有b 为了为奇数 a的等于b 。 所以 最后等亮着的是完全平方的数 

public static void findLights3(int lights,int num) {
		if (num <1) System.out.println("参数错误"); 
		else {
			// 求公约数个数  如果最后是奇数个  灯亮  偶数 灯灭
			int total = 0; //总的亮灯数
			for (int i = 1; i <= lights;i++) {
				for (int j = 1; j<=i && j <= num;j++) {
					if (j*j==i) {
						total++;
					}
				}
			}
			System.out.println("最后亮了 " + total + " 盏灯!");
			
		}
	}

运行效果



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值