该题还可以扩展,比如说给更多的球,如3个球,多少次测试可以找出楼层。
分析如下:
用动态规划解这个问题
设f(a, b)为a个球做b次测试可以测试到的楼层数,可以确定的楼层数即为f(a, b) + 1,因为第1层不需测试,需要测试的楼层号仅仅为[2, f(a, b) + 1]共f(a, b)层,也就是a个球b次测试可以测试到的楼层数。考虑第1次测试,测试的楼层记为x:
1)如果球破了,就需要测试x下面的楼层,还剩下a-1个球b-1次测试,测试的楼层数为f(a - 1, b - 1)。
2)如果球没有破,那么需要测试x上面的楼层,还剩下a个球b-1次测试,测试的楼层数为f(a, b - 1)。
a个球b次测试为1)2)测试的楼层数及第1次测试了的1层,所以:
f(a, b) = f(a - 1, b - 1) + f(a, b - 1) + 1 (1)
考虑初始条件,显然f(a, 1) = 1(a >= 1,1次测试可以测试到的楼层数当然为1,不论多少个球),f(1, b) = b(b >= 1,1个球做了b次测试当然测试到了b层楼)。
强调一下:注意f(a, b)为测试到的楼层数,f(a, b)加上不需测试的楼层才是可以确定的楼层(f(a, b) + 1)。
动态规划解(1)式即可。
一般来说,a >= 2(1个球意义不大),可以计算出f(2, 64) = 2080,f(3, 64) = 43744,f(4, 64) = 679120。
程序如下
-
-
-
-
-
-
-
-
-
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
- #define DEBUG
- #define MAX_B 64
- #define MAX_A 16
- #define f(a, b) ff[a - 1][b - 1]
- static unsigned int a, n;
- static unsigned long long ff[MAX_A][MAX_B];
- static void init()
- {
- int i;
- memset(ff, 0, sizeof(ff));
-
- for (i = 1; i <= MAX_A; i++){
- f(i, 1) = 1;
- }
-
- for (i = 1; i <= MAX_B; i++){
- f(1, i) = i;
- }
- }
- static unsigned long long do_find_min_drops(int i, int j)
- {
- if (f(i, j))
- return f(i, j);
- f(i, j) = do_find_min_drops(i - 1, j - 1) +
- do_find_min_drops(i, j - 1) + 1;
- return f(i, j);
- }
- static void do_print_drops(int i, int j, unsigned long long min,
- unsigned long long max)
- {
- if (min > max)
- return;
- if (1 == i){
- assert(j == max - min + 1);
- for (i = min; i <= max; i++){
- printf("%5d", i);
- }
- printf("/n");
- printf("*************/n");
- return;
- }
- if (1 == j){
- assert(min == max);
- printf("%5lld/n", max);
- printf("*************/n");
- return;
- }
- printf("%5lld", min + f(i - 1, j - 1));
- do_print_drops(i - 1, j - 1, min, min + f(i - 1, j - 1) - 1);
- do_print_drops(i, j - 1, min + f(i - 1, j - 1) + 1, max);
- }
- static void print_drops(int ans)
- {
- do_print_drops(a, ans, 2, n);
- }
- static void find_min_drops()
- {
-
- int i, j, m;
- int ans;
- #if 0//def DEBUG
- for (i = 2; i <= MAX_A; i++){
- for (j = 2; j <= MAX_B; j++){
- printf("f(%d, %d) = %lld/n", i, j, do_find_min_drops(i, j));
- }
- printf("****************/n");
- }
- #endif
- i = 1;
- j = MAX_B;
- while (i <= j){
- m = (i + j) / 2;
- if (do_find_min_drops(a, m) + 1 < n)
-
-
-
- i = m + 1;
- else
- j = m - 1;
- }
- ans = i;
- if (ans > MAX_B){
- printf("the number of the maximum drops(MAX_B = %d) is too small/n", MAX_B);
- printf("maximum floors "
- "can be tested is f(%d, %d) + 1 = %lld + 1. STOP/n", a, MAX_B, f(a, MAX_B));
- exit(0);
- }
- printf("the minimum drops: %d/n", ans);
- print_drops(ans);
- #ifdef DEBUG
- for (i = 1; i <= a; i++){
- for (j = 1; j <= ans; j++){
- printf("f(%d, %d) = %lld/n", i, j, f(i, j));
- }
- printf("****************/n");
- }
- #endif
- }
- int main(int argc, char **argv)
- {
- if (3 != argc){
- fprintf(stderr, "usage: %s a n/n", argv[0]);
- exit(-1);
- }
-
- a = atoi(argv[1]);
- n = atoi(argv[2]);
- printf("a = %d/tn = %d/n", a, n);
- assert(a > 0 && a < MAX_A && n > 0);
- init();
- find_min_drops();
- return 0;
- }
这里,我采用递归的方法打出了测试过程,解释如下:
1)2个球,100层楼时,可以计算出
f(2, 13) = 91
f(2, 14) = 105
因此需要的测试次数为14,测试过程为
15 2 3 4 5 6 7 8 9 10 11 12 13 14
*************
28 16 17 18 19 20 21 22 23 24 25 26 27
*************
40 29 30 31 32 33 34 35 36 37 38 39
*************
51 41 42 43 44 45 46 47 48 49 50
*************
61 52 53 54 55 56 57 58 59 60
*************
70 62 63 64 65 66 67 68 69
*************
78 71 72 73 74 75 76 77
*************
85 79 80 81 82 83 84
*************
91 86 87 88 89 90
*************
96 92 93 94 95
*************
100 97 98 99
*************
第1次测试为15层,如果球破了,则剩下的一个球测试[2, 14],总共的测试次数最多为1+13=14
如果球没破,则测试28层,如果破了,剩下的一个球测试[16, 27],总共的测试次数最多为1+1+12 = 14
...
如果球没破,测试100层,如果破了,剩下的一个球测试[97, 99],总共的测试次数最多为1{11} + 3 = 14
如果球没破,则不存在楼层使得球可以摔破。
2)3个球,100层楼,可以计算出
f(3, 8) = 92
f(3, 9) = 129
因此测试测试最多为9次。测试过程:
38 9 2 3 4 5 6 7 8
第1个球测试38层,如果破了,第2个球测试9层,如果还破了,剩下的一个球测试[2, 8]层,总共的测试次数2 + 7 = 9
*************
16 10 11 12 13 14 15
如果第2个球没破,则测试16层,如果破了,第3个球测试[10, 15],总共的测试测试3 + 6 = 9
*************
22 17 18 19 20 21
如果第2个球没破,则测试22层,如果破了,第3个球测试[17, 21],总共的测试测试4 + 5 = 9
*************
27 23 24 25 26
如果第2个球没破,则测试27层,如果破了,第3个球测试[23, 26],总共的测试测试5 + 4 = 9
*************
31 28 29 30
如果第2个球没破,则测试31层,如果破了,第3个球测试[28, 30],总共的测试测试6 + 3 = 9
*************
34 32 33
*************
36 35
*************
37
*************
67 45 39 40 41 42 43 44
如果第1个球没破,则测试67层,如果破了,第2个球测试45层,如果破了,第3个球测试[39, 44],总共的测试次数3 + 6 = 9。以下类似,不再重复。
*************
51 46 47 48 49 50
*************
56 52 53 54 55
*************
60 57 58 59
*************
63 61 62
*************
65 64
*************
66
*************
89 73 68 69 70 71 72
*************
78 74 75 76 77
*************
82 79 80 81
*************
85 83 84
*************
87 86
*************
88
*************
105 94 90 91 92 93
*************
98 95 96 97
*************
101 99 100
*************
103 102
*************
104
*************
3)对于更多球的情况,输出的测试方法分析起来有些麻烦,但是上面的动态规划法求出的结果就容易理解了,且是保证正确的。