猜数字游戏

20、甲、乙两个人在玩猜数字游戏,甲随机写了一个数字,在[1,100]区间之内,将这个数字写在了一张纸上,然后乙来猜。
如果乙猜的数字偏小的话,甲会提示:“数字偏小”
一旦乙猜的数字偏大的话,甲以后就再也不会提示了,只会回答“猜对 或 猜错”
问: 乙至少猜    多少次  猜可以准确猜出这个数字,在这种策略下,  乙猜的第一个数字是多少???

答案:猜测序列是14,、27、39、50、60、69、77、84、90、95、99
因为无论第几次猜大了,最终的总次数总是14。     这个题目类似于一道Google面试题 :  扔玻璃球求最高楼层。。

一道关于动态规划的面试题——Google面试题:扔玻璃珠
某幢大楼有100层。你手里有两颗一模一样的玻璃珠。当你拿着玻璃珠在某一层往下扔的时候,一定会有两个结果,玻璃珠碎了或者没碎。这幢大楼有个临界楼层。低于它的楼层,往下扔玻璃珠,玻璃珠不会碎,等于或高于它的楼层,扔下玻璃珠,玻璃珠一定会碎。玻璃珠碎了就不能再扔。现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。
首先,为了保存下一颗玻璃珠自己玩,就采用最笨的办法吧:从第一层开始试,每次增加一层,当哪一层扔下玻璃珠后碎掉了,也就知道了。不过最坏的情况扔的次数可能为100。
当然,为了这一颗玻璃珠代价也高了点,还是采取另外一种办法吧。随便挑一层,假如为N层,扔下去后,如果碎了,那就只能从第一层开始试了,最坏的情况可能为N。假如没碎,就一次增加一层继续扔吧,这时最坏的情况为100-N。也就是说,采用这种办法,最坏的情况为max{N, 100-N+1}。之所以要加一,是因为第一次是从第N层开始扔。
不过还是觉得不够好,运气好的话,挑到的N可能刚好是临界楼层,运气不好的话,要扔的次数还是很多。不过回过头看看第二种方式,有没有什么发现。假如没摔的话,不如不要一次增加一层继续扔吧,而是采取另外一种方式:把问题转换为100-N,在这里面找临界楼层,这样不就把问题转换成用递归的方式来解决吗?看下面:
假如结果都保存在F[101]这个数组里面,那么:
F[N]=100-N,
F[100]=min(max(1,1+F[N-1]),max(2,1+F[N-2]),……,max(N-1,1+F[1]));
看出来了没有,其实最终就是利用动态规划来解决这个问题。

折腾n久才把题目的思路想通。

网上题目给的解释的东西总是不怎么符合自己的口味了(有时候还误人子弟啊),老让人想好半天,这时老感觉自己XQ不够用啊,要是可开挂就好了!哎~什么时候开看到些更基础些的呢~毕竟动态规划的东西太灵活了。需要好好想想才可以得出结果啊。

状态:F(N)相当于判断N层楼需要玻璃珠个最少的个数。如果在这N层中的第i层扔一个玻璃球,最多的此次就位max{i, F[N-i]+1},(注意加一,加上本次扔的玻珠,我就忘了这个。)然后在这N层中每一层试试看。找出最小次数作为F(N)={ min( max(1, F(N-1)+1), max(2, F(N-2)+1), ... ,max(N-1, F(1)+1) ) }。终止的条件:F(0)=0,F(1)=1。根据动态规划的思想,使用一个数组保存每个子问题的解,需要时直接取出。

然后又是纸写代码。华丽的递归出来后,调试,错错错。。。

咋一下,递归太深,改非递归。几个细节错误。。

 1 #define MAX(A,B) ((A)>(B)?(A):(B))
 2 
 3 int func12(int N) //
 4 {
 5     int *F;
 6     int min;
 7     if (N<=0)
 8     {
 9         return -1;
10     }
11     F = (int *)malloc((sizeof(int)*(N+1)));
12     memset(F, 0, sizeof(int)*(N+1)); //初始化
13     F[0]=0;
14     F[1]= 1;
15 
16     for (int i=2; i<=N; i++)
17     {
18         min=N;
19         for (int j=1; j<=i; j++)
20         {
21             int tmp = MAX(j, F[i-j]+1);
22             if (min>tmp)
23             {
24                 min = tmp;
25             }
26         }
27         F[i] = min;
28     }
29     int k = F[N];
30 
31     free(F);
32 
33     return k;
34 }
35 
36 //调用
37 
38 cout<<func12(100)<<endl;

递归和回溯等思想还没有真正学会其精髓啊~

不说了,说多了都是泪。。。。

毕。

 

posted @ 2013-03-23 16:27  legendmaner  阅读(710)  评论(0编辑  收藏  举报