poj 1218

大约快一年都没怎么写过代码了,刚刚帮一个朋友翻POJ的题目分类时又想起了这个题目
真的是很有趣的一个题,据说是IT公司的面试题里最经典的之一(另一个是病狗问题)。大概意思如下:一个监狱看守员喝醉了酒,于是把监狱每扇门都打开(假设有n扇门);然后再从1号门开始,隔一扇关一个门(把2的倍数的门关掉);接着再从1号门开始,隔2扇操作一个门(操作3的倍数的门,原来是开的关掉,关着的则打开)。这样一直操作到n的倍数,问最后有多少扇门是打开的。
这个也可以叫关灯问题:有n个灯,分别由n个开关控制,拨一下开关则可以改变灯的状态(开->关 关->开)。初始状态灯都是关着的,先把每个开关都拨一下,然后拨一下2的倍数的开关,接着3的倍数,直到n的倍数,问最后有多少灯是开着的。
很多人的第一反应是开个数组,写个循环模拟一下。但是仔细写下一些小数字之后,可以发现一点规律。与其直接计算打开的门的个数,不如我们先来看看打开的门的号码有没有什么规律。
我先让n=10,结果打开的门的号码是1、4和9,它们的共同特点就是都是完全平方数。我又让n=100,用计算机跑了一下,果然打开的门的号码是1、4、9、16、25、36、49、64、81、100,就是n以内的平方数!
那么如何来证明n号门门打开<->n是完全平方数呢?如果到最后门是打开的话,肯定是操作过奇数次: 开-关-开... 我们假设n号门最后是打开的,那么n号门的操作次数其实就是n的约数个数(逢n的约数才会操作n号门),所以需要n的约数是奇数个。这时又有人想到写一个循环来判断是否n的约数是奇数个。其实只有完全平方数n=i*i满足约数是奇数个,否则有一个约数k ,必定有一个约数n/k,这样约数就是偶数个。对于完全平方数n=i*i,i=n/i,所以约数是奇数个。
这时有人问我怎么求n以内的完全平方数的个数,打表?遍历?其实直接sqrt(n)取整就行了, 至于为什么,令i=(int)sqrt(n), i*i <= n ,所以n以内有i个完全平方数。
到这里全部证明都结束了。原来看《编程珠玑》的时候,里面快速排序的证明非常优美。这道题也让我感觉到了同样的优美:门槛很低,但是做到代码简化到极致成为美丽和优雅却不容易。可能这就是我一直喜欢给喜欢编程的同学推荐这道题的原因之一吧:我总喜欢问他们,代码还可以更短么。当短到不能再短的时候,灵感就出现了。这也是我喜欢读“啊哈,算法”这一章的原因之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值