Google面试题之100层仍两个棋子
一道Google面试题,题目如下:“有一个100层高的大厦,你手中有两个相同的玻璃围棋子。从这个大厦的某一层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略,来得知那个临界层面。“
版本一:
为了得到两个棋子的最优策略,我们先简化问题,看看一个棋子的情况。如果手中只有一个棋子,为了得知临界层面,你只有一种选择:从2楼开始,一层一层地试,直到棋子被打碎,此时你站的楼层就是所求的临界层面。在最差的情况下,我们需要投掷99-2+1=98次,你可能奇怪为什么不是100-2+1=99次,那是因为题目已经告诉我们“从这个大厦的某一层扔下围棋子就会碎”,所以在99层扔下来还没碎的话就不用去100层了——从那里扔它一定会碎。
从一个棋子的策略我们可以看出,一个棋子就足以解答这个问题了。现在又多了一个棋子,该如何利用它呢?很自然地,我们希望能通过这个棋子缩小这种一层一层查找的范围。为了缩小范围,我们将整个大厦的层数分成x段,在这x段中查找那个临界段,然后在临界段中再一层一层地找临界层。比如可以将大楼分成4段,我们分别在25层、50层、75层投掷棋子,以确定临界段;如果临界段在25层到50层,我们再从26层开始一层一层查找临界层。
分析到这里,问题就转化成了如何确定分段数x使棋子投掷的次数最少的问题。在最差的情况下,要确定临界段,我们需要投掷100/x-1次;确定了临界段之后要确定临界层,我们需要再投掷x-1次。因此,问题就成了求函数f(x)=(100/x-1)+(x-1)的最小值问题。先对f(x)求导,f’(x)=1-100/x2,令f’(x)=0求出驻点x=10(x=-10舍去)。由于f(x)存在最小值且只有一个驻点,所以当x=10时f(x)取得最小值,最小值为18。这样就解答了这个问题。(不等式就可以求了)
其实10这个结果也很容易直接看出来。在只有一个棋子时,我们相当于把整个大厦分成了一段,这一段有100层。在有两个棋子时,我们有很多分法,但无论怎么分,如果分成k1段,每段有k2层,那么就有k1k2=100。在最坏的情况下,我们需要投掷(k1-1)+(k2-1)次。因此问题也可以表述成在k1k2=100的条件约束下,如何让函数f(k1,k2)=
k1+k2最小。在初等数学中,我们知道在矩形面积一定的情况下,正方形的周长最小。利用这个结论,我们可以直接得出结论k1=k2=10。
现在问题已经完满解决,但我还想把这个问题扩展一下,把它变成“m层楼n个棋子”的情况。首先来看这样一个问题,给定m层楼,多少个棋子就“足够”了,也就是说,再多的棋子也不能加快查找的过程。在我所能想到的方法里,二分法应该是最优的,如果按二分法来查找,则需要ceiling(log2m)个棋子(ceiling是向上取整函数),超过这个数再多的棋子也无益。
如果n>=ceiling(log2m),那就采用二分法,现在考虑n<
ceiling(log2m)的情况。前面已经看到,当n=2时,问题可以表述成在k1k2=100的条件约束下,求函数f(k1,k2)= k1+k2的最小值。类似地,在n个棋子的情况下,问题可以表述成在k1k2…kn=m的条件约束下,求函数f(k1,k2,…,kn)=k1+k2+…+kn的最小值。利用拉格朗日乘数法,我们可以很容易地求出:当k1=k2=…=kn=n√m时,这个多元函数取得最值。n√m有可能不是整数,因此这只是一个理论上的结果。
我们换一个思路考虑,m层楼n个棋子的问题其实就是如何将m分解成n个因子相乘,从而让各个因子之和最小。如何分解m使得策略最优就成了问题的关键。前面得出的结论提示我们尽量让各个因子相等或者相差较小,它们相加的结果才会较小。比如,100层楼3个棋子的情况,5,5,4应该是一个最优的选择。
考虑到这里,又有一个问题出现了:是不是将m分解的越多越好呢?比如,将100分解成10,10好呢,还是2,5,10好?这个问题其实就是在问,两个大于1的整数,它们的和大呢还是积大。很明显,当然是积大,因此将m分解的越多越好。
数论告诉我们,质数是整数的基础,所有整数都可以分解成若干个质数的乘积。因此,如果将上面的方法发挥到极致,那就要求我们把m分解成质数的乘积。当然,如果棋子足够多,这并不是最优的方法,对质数层楼的段,你仍然可以采用二分法。
------------------------------------------------------------------------------------------------------
上文贴出之后,我又在CSDN和ChinaUnix的论坛看了一些网友的解法,发现上述方法并非最优。将大楼分段以缩小查找范围的想法是没错的,问题在于是否应该均匀分段。
题目要求我们总的投掷次数要最少。在分段之后,总的投掷次数就等于确定临近段的次数加上确定临界层的次数。如果我们均匀分段,则确定临界层的最坏投掷数是固 定的(9次),随着我们确定临近段的投掷次数增加,总的投掷次数也在增加。这样一来,随着临界段的不同,投掷次数也不同。
这也就是为什么上述方法不是最优的原因:投掷次数分布不均。按最坏情况估计,这种方法就多做了几次。为了使最坏情况的投掷数最小,我们希望无论临界段在哪里,总的投掷数都不变,也就是说将投掷数均匀分布。
接下来的解决方案就很容易想出了:既然第一步(确定临界段)的投掷数增加不可避免,我们就让第二步(确定临界层)的投掷数随着第一步的次数增加而减少。第一步的投掷数是一次一次增加的,那就让第二步的投掷数一次一次减少。假设第一次投掷的层数是f,转化成数学模型,就是要求f+(f-1)+...+2+1>=99,即f(f+1)/2>=99,解出结果等于14。
这种方法要推广到n(n>2)个棋子的情况比较困难。我初步的想法是,先用均匀分段求出一个解,然后修正这个解使投掷次数均匀分布。如果你对此有兴趣,不妨思考一下具体的解法。
版本二:
假设N正好等于1+2+...+m,那么我觉得最有的策略就是第一个玻璃球扔在第m层,如果碎了,显然需要剩下的m-1层从底往上一一尝试,最坏情况就是m;假设m处没有碎,问题等价于楼高N'=1+2+...+(m-1)的地方同样的问题需要的次数m'+1 (1就是第一次在m层的尝试),根据我们的递归,容易得到N'对应需要的次数正好是m-1次,因此总次数也是m。
我们的二分应该倾向于不管失败还是成功,两种情况的总检测次数相等。因此这应该是最优的算法。
当然,当N不能表示成1+2+...+m使,我们只能找最小的m作为需要测试的次数。
至于100层楼,显然m=14,我们的第一次扔球应该分别在第14, 如果没碎继续在14+13=27,再没有碎则扔在第27+12=39层,以此类推。最坏需要14次判断。
版本三:
找出一个固定的方案A, 使得对于目标t为任意[1,100]里的数的时候, 找出t要扔的最多的次数 最小
因为t不同的时候, 方案A要扔的次数不一定一样, 我们就是要使得这个最多的次数最小
动态规划就好了
F(l,r,k)为 确定目标t是否在[l,r]中且手上有k个棋子的最少扔子次数, 有状态转移方程:
/ (r-l+1) (k = 1)
F(l,r,k) = | 1 (l = r)
| 0 (l > r)
\ 1+min{max{F(l,mid-1,k-1),F(mid+1,r,k)}} (l<=mid<=r)
写了程序算了一下,是14
#include "stdio.h"
#include "string.h" const int INF = 200000000;
const int maxN = 110; int f[maxN][maxN][maxN];
int n, k; int
find(int l, int r, int k)
{
if (l > r)
{
return 0;
}
if (k == 1)
{
return r - l + 1;
}
if (l == r)
{
return 1;
}
if (f[l][r][k] != -1)
{
return f[l][r][k];
}
int mid;
int left, right, t;
f[l][r][k] = INF;
for (mid = l; mid <= r; ++mid)
{
left = find(l, mid - 1, k - 1);
right = find(mid + 1, r, k);
t = left > right ? left : right;
f[l][r][k] <?= t;
}
return ++f[l][r][k];
} int
main()
{
memset(f, -1, sizeof(f));
while (scanf("%d %d", &n, &k) == 2)
{
printf("%d\n", find(1, n, k));
}
return 0;
}
Google面试题之100层仍两个棋子的更多相关文章
- 【google面试题】求1到n的正数中1出现的次数的两种思路及其复杂度分析
问题描写叙述: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.比如输入12,从1到12这些整数中包括1 的数字有1.10.11和12.1一共出现了5次. 这是一道广为流传的googl ...
- Google 面试题和详解
Google的面试题在刁钻古怪方面相当出名,甚至已经有些被神化的味道.这个话题已经探讨过很多次,而科技博客 BusinessInsider这两天先是贴出15道Google面试题并一一给出了答案,其中不 ...
- Google面试题:计算从1到n的正数中1出现的次数
题目: 输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次. 找工作,准备看写题目,题目说是Goo ...
- 男性在下一100层【第三层】——高仿手机银行client接口
前言: 从<男性在下一100层>系列博文[二楼]现在出版了整整三个月后,.从上述观点和这么多朋友的意见还是比较喜欢真实类的博文. 毕竟我们都叫"攻城狮".所以要看是否这 ...
- 数组中第K小的数字(Google面试题)
http://ac.jobdu.com/problem.php?pid=1534 题目1534:数组中第K小的数字 时间限制:2 秒 内存限制:128 兆 特殊判题:否 提交:1120 解决:208 ...
- Google 面试题:Java实现用最大堆和最小堆查找中位数 Find median with min heap and max heap in Java
Google面试题 股市上一个股票的价格从开市开始是不停的变化的,需要开发一个系统,给定一个股票,它能实时显示从开市到当前时间的这个股票的价格的中位数(中值). SOLUTION 1: 1.维持两个h ...
- 程序员面试题精选100题(33)-在O(1)时间删除链表结点[数据结构]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点.链表结点的定义如下: struct ListNode { ...
- 超多经典 canvas 实例,动态离子背景、移动炫彩小球、贪吃蛇、坦克大战、是男人就下100层、心形文字等等等
超多经典 canvas 实例 普及:<canvas> 元素用于在网页上绘制图形.这是一个图形容器,您可以控制其每一像素,必须使用脚本来绘制图形. 注意:IE 8 以及更早的版本不支持 &l ...
- 『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄
本篇为<『HTML5挑战经典』是英雄就下100层-开源讲座>第二篇,需要用到开源引擎lufylegend,可以到这里下载: 下载地址:http://lufylegend.googlecod ...
随机推荐
- [Form Builder]:CREATE_GROUP Built-in
Description Creates a non-query record group with the given name. The new record group has no colum ...
- 简论数据库乐观悲观锁与并发编程中的CAS
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5783205. ...
- C#垃圾回收机制详解
一.托管代码/非托管代码 C#代码通过C#编译器编译成程序集,程序集由微软中间语言组成,CLR会为程序集开辟一个应用程序域,程序集就是运行在这个应用程序域里面的,应用程序域是相互独立的,互不影响. 托 ...
- Java_web 乱码和一些地址输错的问题(原创)
1.首先记录下java_web的发布问题:安装好了Tomcat和MyEclipse后,从MyEcilpe中自动发布,不需要手动打开Tomcat 2.ipmort别人的程序后,先部署,后run后拉你的T ...
- 学习笔记_过滤器详细_2(过滤器JavaWeb三大组件之一)
过滤器详细 5 四种拦截方式 我们来做个测试,写一个过滤器,指定过滤的资源为b.jsp,然后我们在浏览器中直接访问b.jsp,你会发现过滤器执行了! 但是,当我们在a.jsp中request.getR ...
- xcode编译运行报错纪录(持续更新)
---恢复内容开始--- 1. Undefined symbols for architecture i386: "_deflate", referenced from: -[NS ...
- 你喜欢使用eclipse+tomcat编程吗?!
在eclipse中配置tomcat简直是一场灾难! 开源软件确实给开发者极大的自由,但,同时也带来额外的麻烦. eclipse+tomcat只是其中之一.我有幸碰到了N次,在N+1次时,不得不提笔撰文 ...
- Windows下Eclipse+PyDev配置Python开发环境
1.简介 Eclipse是一款基于Java的可扩展开发平台.其官方下载中包括J2EE.Java.C/C++.Android等诸多版本.除此之外,Eclipse还可以通过安装插件的方式进行包括Pytho ...
- Codevs 3731 寻找道路 2014年 NOIP全国联赛提高组
3731 寻找道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找 ...
- Headfirst设计模式的C++实现——装饰者模式(Decorater)
Beverage.h #ifndef BEVERAGE_H_INCLUDED #define BEVERAGE_H_INCLUDED #include <string> class Bev ...