看了李永乐老师讲解的双蛋问题,觉得很有趣,就按照视频里的思路自己实现一个吧。
双蛋问题,实际题面为T层楼,N个蛋,最小扔多少次蛋一定能找出碎蛋的临界楼层?
解题思路实为递归,这里就不多废文字了,有兴趣的也可以去B站av96214853观看李永乐老师的讲解该视频,更容易理解。
直接上代码
#include <stdio.h>
#define FLOORS 2000
#define EGGS 10
int res[FLOORS+1][EGGS+1];
int CAL1(int k, int floors, int eggs)
{
int broken = CAL(k - 1, eggs-1);
int notbroken = CAL(floors-k, eggs);
int ret = broken > notbroken? broken+1:notbroken+1;
return ret;
}
int CAL(int floors, int eggs)
{
if (floors == 0 || eggs == 0)
return 0;
if (res[floors][eggs] != 0) { //calculated already
return res[floors][eggs];
}
int i = 0;
int min = 0;
for (i = 1; i <= floors; i++) {
int k = CAL1(i, floors, eggs);
if (min == 0)
min = k;
else
min = k < min? k:min;
}
res[floors][eggs] = min;
return min;
}
#define INCREASE(x) \
do { \
if (x < 25) \
x++; \
else if (x < 50) \
x+=5; \
else if (x < 100) \
x = 100; \
else if (x < 500) \
x += 100; \
else if (x < 1000) \
x = 1000; \
else \
x++; \
}while(0)
int main()
{
int i,j;
//init array
// only 1 egg
for (i = 1; i <= FLOORS; i++) {
res[i][1] = i;
}
// only 1 floor
for (j = 1; j <= EGGS; j++) {
res[1][j] = 1;
}
printf(" ");
for (i = 1; i<=EGGS; i++) {
printf("%-4d ", i);
}
printf("\n");
i = 1;
while(i <= 1000) {
printf("floor%-5d", i);
for (j = 1; j <= EGGS; j++) {
printf("%-4d ", CAL(i,j));
}
printf("\n");
INCREASE(i);
}
return 0;
}
运行结果
[ckun@localhost eggs]$ gcc -g eggs.c -o test
[ckun@localhost eggs]$
[ckun@localhost eggs]$ ./test
1 2 3 4 5 6 7 8 9 10
floor1 1 1 1 1 1 1 1 1 1 1
floor2 2 2 2 2 2 2 2 2 2 2
floor3 3 2 2 2 2 2 2 2 2 2
floor4 4 3 3 3 3 3 3 3 3 3
floor5 5 3 3 3 3 3 3 3 3 3
floor6 6 3 3 3 3 3 3 3 3 3
floor7 7 4 3 3 3 3 3 3 3 3
floor8 8 4 4 4 4 4 4 4 4 4
floor9 9 4 4 4 4 4 4 4 4 4
floor10 10 4 4 4 4 4 4 4 4 4
floor11 11 5 4 4 4 4 4 4 4 4
floor12 12 5 4 4 4 4 4 4 4 4
floor13 13 5 4 4 4 4 4 4 4 4
floor14 14 5 4 4 4 4 4 4 4 4
floor15 15 5 5 4 4 4 4 4 4 4
floor16 16 6 5 5 5 5 5 5 5 5
floor17 17 6 5 5 5 5 5 5 5 5
floor18 18 6 5 5 5 5 5 5 5 5
floor19 19 6 5 5 5 5 5 5 5 5
floor20 20 6 5 5 5 5 5 5 5 5
floor21 21 6 5 5 5 5 5 5 5 5
floor22 22 7 5 5 5 5 5 5 5 5
floor23 23 7 5 5 5 5 5 5 5 5
floor24 24 7 5 5 5 5 5 5 5 5
floor25 25 7 5 5 5 5 5 5 5 5
floor30 30 8 6 5 5 5 5 5 5 5
floor35 35 8 6 6 6 6 6 6 6 6
floor40 40 9 6 6 6 6 6 6 6 6
floor45 45 9 7 6 6 6 6 6 6 6
floor50 50 10 7 6 6 6 6 6 6 6
floor100 100 14 9 8 7 7 7 7 7 7
floor200 200 20 11 9 8 8 8 8 8 8
floor300 300 24 13 10 9 9 9 9 9 9
floor400 400 28 14 11 10 9 9 9 9 9
floor500 500 32 15 11 10 10 9 9 9 9
floor1000 1000 45 19 13 11 11 11 10 10 10
对比结果,完全一致。
一点思考:
这种递归问题,如果不利用计算机,人力计算的时间损耗巨大。
代码若再稍加改进,也可以算出扔蛋的最优解,及第一次扔第几层,若碎,第二次扔第几层,若不碎第二次扔第几层.....以此类推。从而生成一个操作步骤的树(二叉树),这颗二叉树的深度也就是最小扔蛋次数(一定能找到临界楼层的)。
操作步骤树就可以当做实际手动操作指南,能够最快速找到临界楼层。