两个玻璃球问题(Google)

来源:互联网 发布:网络用语污是什么意思 编辑:程序博客网 时间:2024/06/11 14:06

本文根据多篇网上的文章进行整理。

甲、乙两个人在玩猜数字游戏,甲随机写了一个数字,在[1,100]区间之内,将这个数字写在了一张纸上,然后乙来猜。
如果乙猜的数字偏小的话,甲会提示:“数字偏小”
一旦乙猜的数字偏大的话,甲以后就再也不会提示了,只会回答“猜对 或 猜错”
问: 乙至少猜    多少次  猜可以准确猜出这个数字,在这种策略下,  乙猜的第一个数字是多少???
答案:猜测序列是14,、27、39、50、60、69、77、84、90、95、99
因为无论第几次猜大了,最终的总次数总是14。     这个题目类似于一道Google面试题 :  扔玻璃球求最高楼层。
英文叙述为:
Dropping Balls
You have to do an experiment to determine the highest floor on a 100-floor building from which a manufactured snooker ball may be dropped without breaking. 

You are given two identical snooker balls, which you can drop from various floors of the building, to carry out your experiment. 

If a ball doesn't break after being dropped, it may be reused without suffering any loss of quality. But if both balls break before you have determined the highest floor, then you are an incompetent bungler and your boss is ultimately going to fire you.

What is the least number of times you must drop the snooker balls in order to determine the highest floor?

下面从三个层面来分析这道题目。
1.最优解是多少,如何证明?
引自知乎:
这个题目首先是关于“最优”的定义。
考虑best-worse case最坏情况下最优。也就是说假如你的算法是从第一楼逐楼往上试,那么相应最坏的情况是在100楼破,相应的是一百次。

这种情况下最优策略也就是匿名用户提到的从14楼开始递减间隔的办法,worst case 需要14次。

解法:
记n层s球的问题为Q(n,s),对应的最坏情况最优解为ba(n,s);

一些简单的结果:
(0) ba(m,2)>=ba(n,2) 如果m>n,trivial.
(1) ba(n,1)=n
当你只剩下一个球,为了能够检验出临界点,你只能逐层检验,最坏情况下所需的检验次数为n;
(2)ba(1,2)=1
(3)iterative: 假设你从k层扔球,有两种情形:
  1. 球破。那么临界层必然在1层到k-1层之间,剩下一球,由(1)得出,最坏情况最优所需的步数为: 1 + ba(k-1,1)=k;
  2. 球不破。问题变成n-k层两球的问题Q(n-k,2), 所以最坏情况最优所需步数是:1+ba(n-k,2);
综合1,2,最坏情况所需步数: ba(n,2)=\max\{k,1+ba(n-k,2)\}
当k=1+ba(n-k,2)的时候,
ba(n,2)=ba(n-k,2)+1
结合(2),(3),由(2)迭代得知:
当n = 1+2+3+...+k
ba(n,2)=k
当k=13时, n=91;
ba(100,2)=max(9,1+ba(91,2))=14

所以100层,最坏情况最优策略的步数是14.
2.如果通过程序的方式进行求解?


假如结果都保存在F[101]这个数组里面,那么:
F[100]=min(max(1,1+F[N-1]),max(2,1+F[N-2]),……,max(N-1,1+F[1]));
看出来了没有,其实最终就是利用动态规划来解决这个问题。
下面是自己随便写的C++代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. int dp[101] = { 0 };  
  5.   
  6. void solve()  
  7. {  
  8.     int i , j , k;  
  9.     for(i = 2 ; i < 101 ; ++i)  
  10.     {  
  11.         dp[i] = i;  
  12.         for(j = 1 ; j < i ; ++j)  
  13.         {  
  14.             k = (j>=(1 + dp[i-j])) ? j : (1 + dp[i-j]);  
  15.             if(dp[i] > k)  
  16.                 dp[i] = k;  
  17.         }  
  18.     }  
  19. }  
  20.   
  21. int main(void)  
  22. {  
  23.     dp[0] = 0 , dp[1] = 1;  
  24.     solve();  
  25.     printf("%d\n",dp[100]);  
  26.     return 0;  
  27. }  
输出结果为14。也就是说,最好的方式只要试14次就能够得出结果了。
第三:每次到底怎么扔?

Our Solution:

The answer is: 14

You drop the first snooker ball from the 14th floor. If it breaks, you can then determine the highest floor by dropping the second snooker ball no more than 13 times (drop it from the 1st floor, and if it doesn't break, drop it from the 2nd floor, and if it still doesn't break, drop from the 3rd, etc).

If the first ball survives the drop from the 14th floor, you then drop it from the 27th floor (14 + 13 = 27). If it breaks, you can complete your test in no more than 12 drops with the second ball by dropping it between the floors 15 to 26.

If from the 27th floor the first ball still doesn't break, the next floor to drop it from is the 39th (14 + 13 + 12 = 39). If it breaks, drop the second ball from floors 28 to 38 (max 11 drops).

Repeat the experiment the same way whenever the first ball doesn't break; after the 39th floor should be the 50th floor (14+13+12+11), then the 60th floor (14+13+12+11+10), and so on. If the first ball survives 11 drops, you will be on the 99th floor. In that case, it only takes one more drop to complete the whole test.

(Puzzle and solution courtesy of JaneFairfax
0 0
原创粉丝点击